看一看这个:
#include <iostream>
#include <memory>
using Foo = int;
using FooPtr = std::shared_ptr<Foo>;
FooPtr makeFoo()
{
FooPtr f{
new Foo(),
[](Foo* ptr) {
delete ptr;
std::cerr << "!\n";
}
};
return f;
}
void bar(FooPtr p = {})
{
p = makeFoo();
}
int main()
{
bar();
}
// Expected output: '!'
// Failure case: no output (deleter not invoked?)我期望shared_ptr删除器在bar()返回时被调用,在使用GCC 4.8.5的64位CentOS 7系统上,它会调用。
然而,在我的32位CentOS 6系统上使用GCC 4.8.2下的devtoolset-2 (我也认为在gcc-linaro-arm-linux-gnueabihf-4.8-2013.10_linux下,我的覆盆子Pi工具链),它没有。
看看代码,并考虑到C++11在4.8中的实验特性,我觉得这闻起来像是一个编译器bug。但我也可能在某个地方掉进了UB陷阱(或者只是一般地误解了这些东西应该如何工作)。
谁有错?我该怎么解决呢?
工作上
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)失败继续
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/opt/rh/devtoolset-2/root/usr/libexec/gcc/i686-redhat-linux/4.8.2/lto-wrapper
Target: i686-redhat-linux
Configured with: ../configure --prefix=/opt/rh/devtoolset-2/root/usr --mandir=/opt/rh/devtoolset-2/root/usr/share/man --infodir=/opt/rh/devtoolset-2/root/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --enable-languages=c,c++,fortran,lto --enable-plugin --with-linker-hash-style=gnu --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.2-20140120/obj-i686-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.2-20140120/obj-i686-redhat-linux/cloog-install --with-mpc=/builddir/build/BUILD/gcc-4.8.2-20140120/obj-i686-redhat-linux/mpc-install --with-tune=generic --with-arch=i686 --build=i686-redhat-linux
Thread model: posix
gcc version 4.8.2 20140120 (Red Hat 4.8.2-15) (GCC)发布于 2018-03-26 19:15:21
正如内森所显示的,我对指针生命周期的假设是标准正确的。
删除者并没有被引用,这似乎是GCC或libstdc++的错误,考虑到链接的评论解决了这个问题,症状似乎相似,而且在GCC 4.8.5之前就已经修复了,这可能是bug 60367的错误。
用= {}代替= FooPtr{}似乎是一个可行的解决办法。
注意,在类似的情况下,也有可能导致不良行为的7.2中的回归和一些更老的"8.0“主干构建 (谢谢阿恩·沃格尔!)。
发布于 2018-03-26 18:44:13
应该在bar返回时或在调用bar的完整表达式的末尾调用析构函数。
如果我们查看expr.all/4 (C++17草案),我们有
当一个函数被调用时,每个参数(11.3.5)都应该初始化(11.6,15.8,15.1)及其对应的argument....It -定义参数的生存期是在定义它的函数返回时还是在封闭的全表达式结束时.
因此,应该在函数开始时将p初始化为空FooPtr,移动指定的MakeFoo返回,然后在bar末尾或bar返回main之后最终销毁(依次调用删除器)。
https://stackoverflow.com/questions/49498090
复制相似问题