Copying and destruction when returning a C++ object

c++, object, return, visual-studio, visual-studio-2012

Solution

This is because your code violates the rule of three: since you do not have a copy constructor, something important happens behind the scene for which you do not see a printout.

When you do not have a copy constructor, C++ happily defines one for you. This is usually the exact constructor that you want, except in one case: when your class manages resources explicitly. In cases like that, copying content byte-for-byte creates a false alias, when the same pointer can be deleted more than once. When you turn on optimizations, the compiler skips the calls of the copy constructor (return value optimization). With optimizations off, however, the copy constructor gets called, and then the copy of the `m_ptr` gets deleted, leaving the actual pointer pointing to deleted memory.

Here is how to fix this:

PG& operator =(const PG& src) {
    *m_ptr = *(other->m_ptr);
    printf("Assigned PG %x %x\n", (void*)m_ptr, (void*)src.m_ptr);
    return(*this);
}
PG(const PG& other) {
    m_ptr = new int;
    *m_ptr = *(other->m_ptr);
    printf("Copied PG %x\n", (void*)m_ptr);
}

Note: converting pointers to `int` is not defined; you should convert pointers to `void*`, and print with `%x` format specifier.

Problem

I have a fairly simple piece of test code: ``` #include <stdio.h> class PG { public: PG(){ m_ptr = new int; printf("Created PG %i\n", (int)m_ptr); } ~PG(){ printf("Deleted PG %i\n", (int)m_ptr); delete (m_ptr); } PG& operator =(const PG& src) { printf("Copied PG %i %i\n", (int)m_ptr, (int)src.m_ptr); return(*this); } private: int * m_ptr; }; PG CreatePG() { PG ret; return ret; } int main(int argc, char* argv[]) { PG test; test = CreatePG(); printf("Ending\n"); return 0; } ``` If I compile this with GCC, VS2008 or VS2012 with full optimization and run it I get exactly what I expect: Created PG 7837600 -created test Created PG 7689464 -created ret Copied PG 7837600 768946 -copied ret to test Deleted PG 7689464 -deleted ret Ending Deleted PG 7837600 -deleted test However when I compile on VS2008 or VS2012 with no optimization I get this: Created PG 3888456 -created test Created PG 4036144 -created ret Deleted PG 4036144 -deleted ret. Hang on, we haven't copied it yet! Copied PG 3888456 4036144 -We are now trying to copy deleted data Deleted PG 4036144 -This has already been deleted. The application crashes I can't believe that it is a bug in VS that has never been fixed but I also can't see what I am doing wrong. In my application I have an instance where this behaviour also occurs when compiling a more complicated class optimized for speed. I know it would be more efficient to use: ``` PG test = CreatePG(); ``` but I still get a similar problem though it is obviously using copy elision in this case: Created PG 11228488 Deleted PG 11228488 Ending Deleted PG 11228488 I am still getting the double delete. If anyone can throw some light on this I would be very grateful.

Original source