std::shared_ptr 和初始化列表

Posted

技术标签:

【中文标题】std::shared_ptr 和初始化列表【英文标题】:std::shared_ptr and initializer lists 【发布时间】:2012-08-02 23:50:11 【问题描述】:

std::shared_ptr 构造函数的行为不符合我的预期:

#include <iostream>
#include <vector>

void func(std::vector<std::string> strings)

    for (auto const& string : strings)
    
        std::cout << string << '\n';
    


struct Func

    Func(std::vector<std::string> strings)
    
        for (auto& string : strings)
        
            std::cout << string << '\n';
        
    
;

int main(int argc, const char * argv[])


    func("foo", "bar", "baz");
    Func("foo", "bar", "baz");
    //auto ptr = std::make_shared<Func>("foo", "bar", "baz"); // won't compile.
    //auto ptr = std::make_shared<Func>"foo", "bar", "baz"; // nor this.
    return 0;

我做错了什么还是编译器?编译器是:

$ clang++ --version Apple clang 4.0 版(tags/Apple/clang-421.0.57)(基于 LLVM 3.1svn)

编辑:shared_ptr 而不是 make_shared。

这是错误:

make -k 
clang++ -std=c++11 -stdlib=libc++    main.cc   -o main
main.cc:28:18: error: no matching function for call to 'make_shared'
      auto ptr = std::make_shared<Func>("foo", "bar", "baz");
                 ^~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/c++/v1/memory:4621:1: note: candidate function not viable:
     requires 0 arguments, but 1 was provided
make_shared(_Args&& ...__args)
^
1 error generated.

【问题讨论】:

【参考方案1】:

试试这个:

auto ptr = std::make_shared<Func>(std::initializer_list<std::string>"foo", "bar", "baz");

Clang 不愿意推断"foo", "bar", "baz" 的类型。我目前不确定这是否是该语言应该工作的方式,或者我们是否正在查看编译器错误。

【讨论】:

上次我听说,当涉及到初始化列表时,完美转发实际上并不完美。 "foo", "bar", "baz" 不是表达式,因此没有类型(与 auto 一起使用时除外).. 虽然会很好 "foo", "bar", "baz" 可以是 std::stringchar [][]wchar_t [][].... 的数组。编译器必须确切知道它需要创建什么。【参考方案2】:

shared_ptr&lt;T&gt; 的构造函数将T* 类型的指针作为其参数,假定指向动态分配的资源(或至少可以被删除器释放的资源)。另一方面,make_shared 为您进行构造并直接获取构造函数参数。

所以要么你这么说:

std::shared_ptr<Foo> p(new Foo('a', true, Blue));

或者,更好更高效:

auto p = std::make_shared<Foo>('a', true, Blue);

后一种形式为您处理分配和构造,并在此过程中创建更有效的实现。

你当然也可以说make_shared&lt;Foo&gt;(Foo('a', true, Blue)),但这只会创建一个不必要的副本(可能会被省略),更重要的是它会产生不必要的冗余。 [编辑]对于初始化你的向量,这可能是最好的方法:

auto p = std::make_shared<Func>(std::vector<std::string>("a", "b", "c"));

不过,重要的一点是,make_shared为您执行动态分配,而 shared-ptr 构造函数,而是接受所有权

【讨论】:

"但这只会创建不必要的副本" 不必要的举动。 @ildjarn:嗯,这一切都取决于,不是吗?无论如何,“移动”只是一个优化的副本:-)【参考方案3】:

如果你想创建一个新对象,你需要使用make_shared,这个对象由这些参数构造,由shared_ptr 指向。 shared_ptr&lt;T&gt; 就像一个指向T 的指针——它需要用一个指向T指针 来构造,而不是T

编辑:当涉及初始化列表时,完美的转发实际上并不完美(这很糟糕)。这不是编译器中的错误。您必须手动创建Func 类型的右值。

【讨论】:

抱歉,问题出在 make_shared 上。我在 futzing 时将其更改为 shared_ptr。

以上是关于std::shared_ptr 和初始化列表的主要内容,如果未能解决你的问题,请参考以下文章

智能指针std::shared_ptr初始化时可能泄露的地方

C++:如何初始化以下 std::shared_ptr 构造函数数组

从 'B *' 到 'std::shared_ptr<A>' 的函数式转换没有匹配的转换

[C++11]shared_ptr共享智能指针的初始化与使用

在单元测试中初始化 unique_ptr

`std::optional` 比 `std::shared_ptr` 和 `std::unique_ptr` 有啥优势?