Created attachment 36420 [details] pre-processed C++11 file exhibiting this behavior The problem occurs on line 23813 of the provided .ii file. An object initialized with specific parameters is dealloc'd once before moving, and once after moving, while the target of the move is never dealloc'd. This demo is simplified from a program I'm writing that has to assign an object with an embedded pointer. In the original, this object is destroyed twice separately, resulting in a double free on the pointer. In the demo there is no pointer member, but the undesired behavior is the same. The workaround featured in the demo is the same one that fixed the real program. This problem appears to exist on dialects of C++, at least from '03 onward, but I chose to use C++11, because move constructors can be explicitly declared. In C++03, it does the move in the same manner. compilation command: c++ -g -O0 -std=c++11 -save-temps -o test test.cpp GCC info: Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04) OS description: Ubuntu 3.13.0-48.80-generic 3.13.11-ckt16
compiler output: -*- mode: compilation; default-directory: "~/compiler-test/" -*- Compilation started at Wed Sep 30 00:45:55 ./compile.sh Compilation finished at Wed Sep 30 00:45:55 the command: ./test
I don't see a bug here, could you please try a supported release and explain exactly what output you are seeing and what you expect to see.
Oh, are you expecting this: a_thing = demo(demo::second); to have the same behaviour as this: a_thing.~demo(); new(&a_thing) demo(demo::second); ? That's not how C++ works.
(In reply to Jonathan Wakely from comment #3) > Oh, are you expecting this: > > a_thing = demo(demo::second); > > to have the same behaviour as this: > > a_thing.~demo(); > new(&a_thing) demo(demo::second); > > ? > > That's not how C++ works. I don't expect the same behavior, however I expect the same end result: for the destructor to be called on to be called on the named variable before the move, then for it to be called on the temporary object.
Whoops! Sorry about the malformed double-post. Another way of explaining the problem is that the compiler appears to be suppressing the wrong destructor call. Since this is a move and not a copy, or in C++03 it's a copy elision, it should be suppressing the destructor call on the temporary variable. It's not doing this though; it's suppressing the first destructor call on the named variable instead. When I get a chance, I'll build a GCC for testing purposes. What version would be appropriate in this case? Is 4.8.5 supported?
(In reply to Adam Wenocur from comment #6) > Another way of explaining the problem is that the compiler appears to be > suppressing the wrong destructor call. Since this is a move and not a copy, > or in C++03 it's a copy elision, No, you can't elide an assignment to an existing variable. > it should be suppressing the destructor > call on the temporary variable. It's not doing this though; it's > suppressing the first destructor call on the named variable instead. No, that's not how C++ works. > When I get a chance, I'll build a GCC for testing purposes. What version > would be appropriate in this case? Is 4.8.5 supported? No, the currently supported versions are listed on the home page, https://gcc.gnu.org/ The oldest supported release is 4.9.3
Specifically, a move assignment doesn't destroy anything, it just performs an assignment. So the named variable is not destroyed, its move assignment operator is called, which does whatever it is written to do. The temporary is destroyed at the end of the expression, moving from it doesn't alter its lifetime in any way. The named variable is destroyed at the end of the block as usual, move assigning to it doesn't alter its lifetime in any way. There are online compilers you can use to check the results from various GCC and Clang releases, e.g. http://melponlorg/wandbox You will find none of them runs a destructor on the target of a move assignment, because that's not how C++ works.