- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
[cpp]// Predeclare the derived class so that it can be used for type casting class CDerived; // Define the base class class CBase { public: int nRows; CBase(int n=0) : nRows(n) { } // Cast this class to the derived class to allow the reference operator // to work with the Proxy function. For example: // CDerived A; // CDerived& B = A.Proxy(4); operator CDerived&() { return reinterpret_cast(*this); } // Create a function that does nothing but return // an initialized object of this class type. CBase Proxy(int n) { return CBase(n); } }; // Define the derived class class CDerived : public CBase { public: CDerived(int n0=0) : CBase(n0) { } // Create a function that does nothing but return // an initialized object of this class type. CDerived ProxyA(int n) { return CDerived(n); } }; int main() { // Create a reference to the object returned by the ProxyA function // This all works fine CDerived M(4); CDerived& M0_ref = M.ProxyA(3); CDerived& M1_ref = M.ProxyA(5); // Create a reference to the object returned by the Proxy function CDerived N(4); CDerived& N0_ref = N.Proxy(3); // So far, everything is fine. The next line causes a problem. // N1_ref ends up being placed at the memory location of N0_ref, so it // ends up overwriting N0_ref. CDerived& N1_ref = N.Proxy(5); return 0; }[/cpp]
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I just tried it with 11.1.067, and don't see any issues there either.
test>icl test.cpp
Intel C++ Compiler Professional for applications running on IA-32, Version 11.1 Build 20100806 Package ID: w_cproc
_p_11.1.067
Copyright (C) 1985-2010 Intel Corporation. All rights reserved.
test.cpp
Microsoft Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
-out:test.exe
test.obj
test>test
test>cl test.cpp
Microsoft 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
test.cpp
Microsoft Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:test.exe
test.obj
test>test
test>
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The compiler command line is:
/c /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /EHsc /RTC1 /MDd /GS /fp:fast /Fo"Debug/" /W3 /nologo /Wp64 /ZI
and for the linker:
kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /OUT:"D:\Visual C++\trash\Intel Compiler Bug\Debug\Intel Compiler Bug.exe" /INCREMENTAL /nologo /MANIFEST /MANIFESTFILE:"Debug\Intel Compiler Bug.exe.intermediate.manifest" /TLBID:1 /DEBUG /PDB:"D:\Visual C++\trash\Intel Compiler Bug\Debug\Intel Compiler Bug.pdb" /SUBSYSTEM:CONSOLE /IMPLIB:"D:\Visual C++\trash\Intel Compiler Bug\Debug\Intel Compiler Bug.lib" /MACHINE:X86
What I'm seeing is that the assignment to N1_ref overwrites the assignment to N0_ref. When I look at &N1_ref and &N0_ref in the debugger, they're both the same value. I get the same behavior in both debug and release builds. Any ideas on other things to check?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This looks like aproblem in the compiler. I will investigate this issue and provide an update once I have a resolution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Are you expecting
CDerived&N0_ref=N.Proxy(3);
to allocate an object instead of re-initializing N?
CDerivedN(4); // create CDerived object N,initialized to 4
CDerived&N0_ref=N.Proxy(3); // make reference to N, reinitialize to 3
CDerived&N1_ref=N.Proxy(5);// make reference to N, reinitialize to 5
Afteryou step through the ctor of N(4) don't you see N.nRows transition from 4, 3, 5?
Jim
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Base on the test case above, this is what I see:
CDerived N(4);
CDerived& N0_ref = N.Proxy(3);
CDerived& N1_ref = N.Proxy(5);
std::cout << "N.nRows= " << N.nRows << std::endl << "N0_ref.nRows = "<< N0_ref.nRows << std::endl << "N1_ref.nRows = "<< N1_ref.nRows << std::endl;
Looks like ICL is re-initializing N, but MSVC is allocating an object instead of re-initializing.
MSVC
====
N.nRows= 4
N0_ref.nRows = 3
N1_ref.nRows = 5
ICL
====
N.nRows= 4
N0_ref.nRows = 5
N1_ref.nRows = 5
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
yes, this is the behavior I'm seeing from ICL
N.nRows= 4
N0_ref.nRows = 5
N1_ref.nRows = 5
The thing that has me bothered about ICL "reinitializing" the object is that when I look at &N0_ref and &N1_ref, they're the same using ICL but not MSVC. Shouldn't the addressesalways be different as they're diffent named variables?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
int a;
int& a0_ref = a;
int& a1_ref = a;
The compilers apparently treat a0_ref and a1_ref as though they were in an anonymous union. I didn't realize that. I guess then I really need to understand which compiler is exhibiting the more accepted behavior for this case.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The compiler that is generating the different addresses is (arguably) in error.
Try:
[bash]CDerived N(4); std::cout << "CDerived N(4); " << N.nRows; << std::endl CDerived& N0_ref = N.Proxy(3); std::cout << "CDerived& N0_ref = N.Proxy(3); " << N.nRows; << std::endl CDerived& N1_ref = N.Proxy(5); std::cout << "CDerived& N1_ref = N.Proxy(5); " << N.nRows; << std::endl [/bash]
Your Proxy/ProxyA return (ctor of object), as written,will (may)create an on-stack temporary object that immidately evaporates. Depending on "implementation detail" how stack temps are created will depend on whether this appears to be an anonomous union or seperated structs.
Correct me if I am wrong, I assume that you intend to reissue the ctor on CBase of the object N (of type CDerived) as opposed to creating seperate objects.
You cannot have multiple references to the same object of which that same object contains different states.
If you want seperate states then instantiate seperate objects.
If you want state changes to the same object where state change is effected upon creation of the reference, then the syntax gets a bit obscured (untested code)
[bash] CDerived ProxyA(int n) { return *( new(static_cast(this)) CBase(*this)(n) ); } [/bash]
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The short answer to why I care is that I havea problem that I think can be bettersolved by byrvalue references than my current implementation, but the intel compiler doesn't currently support them. In trying to simulate certain aspects of the design using ICL, I ran into this issue which looked like a bug to me, and since bugs may appear in other more standard cases, I thought it should be reported. In addition, I've learned a bit more about how compilers work.
Thanks,
Robert
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
rvalue references is now supported with the compiler that comes with Intel Parallel Composer 2011 suite. You need to enable the option below.
icl -Qstd=c++0x test.cpp
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Correct me if I am wrong, I very well could be as I am not up on the intricacies of this issue. Aren't R-value references valid only through the end of the current statement? IOW to facilitate use for args in function call and for source object for copy constructors?
My interpretaton of what you are trying to do is to make an R-value (newly constructed)reference persistant past the end of a statement.
Dmitriy, would you have a comment on this?
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
We havefinished investigating this issue, and we have determinedthat thisis not a compiler problem, and the user should make the appropriate changes in the code.
The problematiccodeare listed here:
CDerived N(4);
CDerived& N0_ref = N.Proxy(3);
CDerived& N1_ref = N.Proxy(5);
std::cout << N0_ref.nRows;
The problem with this code is that it is accessing a temporary that is no longer valid. A temporary is created for the return value of N.Proxy(3) but its lifetime is that of the full expression. If this class had a destructor you would see that the destructor for this temporary would occur before the N.Proxy(5) call. Obviously you do not want to access an object that is already destructed.
So,Intel compiler, to reduce the size of the stack, reuses that temporary the next time it is needed. Microsoft instead appears to not reuse the temporary so it remains on the stack. Microsoft still does call the destructor at the end of the full expression though so this is obviously very dangerous and non-portable code.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page