c++ - 我是否误解了这个默认参数 shared_ptr 的范围?

标签 c++ gcc shared-ptr libstdc++ default-arguments

看看这个:

#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 系统上,在 devtoolset-2 下使用 GCC 4.8.2(我认为gcc-linaro-arm-linux-gnueabihf-4.8-2013.10 下_linux,我的 Raspberry Pi 工具链),它没有。

查看代码,考虑到 C++11 在 4.8 中的实验性质,这对我来说就像一个编译器错误。但我也可能在某个地方陷入 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)

最佳答案

析构函数应该在 bar 返回时或在调用 bar 的完整表达式结束时调用。

如果我们查看 [expr.call]/4(C++17 草案),我们有

When a function is called, each parameter (11.3.5) shall be initialized (11.6, 15.8, 15.1) with its corresponding argument.[...]It is implementation-defined whether the lifetime of a parameter ends when the function in which it is defined returns or at the end of the enclosing full-expression.[...]

所以p应该在函数开始时被初始化为空的FooPtr,移动赋值给MakeFoo的返回值,最后在 bar 末尾或 barmain 中返回后销毁(依次调用删除器)。

关于c++ - 我是否误解了这个默认参数 shared_ptr 的范围?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49498090/

相关文章:

c - 编译C文件的问题

c++ - 将自身从拥有它的容器中删除的shared_ptr,有更好的方法吗?

c++ - 清空模板参数以节省空间

c++ - 交叉编译错误 "arm-none-eabi-g++ cannot find entry symbol"

c - 替代 volatile ?

c - 无法在 docker 镜像上执行 arm-cc ( ubuntu 12.04 base )

c++ - 全局智能指针未正确清理

c++ - 将 shared_ptr 或 unique_ptr 传递给 _beginthreadex

c++ - 使用 std::forward 进行参数包扩展的 '...' 的语法

c++ std::types 而不是相应的 c 类型