从unique_ptr创建一个shared_ptr [英] creating a shared_ptr from unique_ptr

查看:195
本文介绍了从unique_ptr创建一个shared_ptr的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我最近评论过的一段代码中,用 g ++ - 4.6 编译的代码,我遇到了一个奇怪的尝试来创建一个 std :: std :: unique_ptr

   >的std ::的unique_ptr<富> foo ... 
std :: make_shared< Foo>(std :: move(foo));

这对我来说似乎很奇怪。这应该是 std :: shared_ptr< Foo>(std :: move(foo)); afaik,尽管我对动作并不熟悉(我知道<$



使用此SSC上的不同编译器进行检查(NUC * )E

  #include< memory> 

int main()
{
std :: unique_ptr< int> foo(new int);
std :: make_shared< int>(std :: move(foo));
}

编译结果:


  • g ++ - 4.4.7给出编译错误

  • g ++ - 4.6.4编译时没有任何错误
  • g ++ -4.7.3给出内部编译器错误
  • g ++ - 4.8.1给出编译错误
  • clang ++ - 3.2.1编译没有任何错误


    所以问题是:哪个编译器在标准方面是正确的?标准要求这是一个无效的声明,一个有效的声明或者这是简单的未定义?



    加法



    我们已经同意,其中一些编译器(如clang ++和g ++ - 4.6.4)允许转换,而不应该转换。然而,使用g ++ - 4.7.3(它在 std :: make_shared< Foo>(std :: move(foo)); )上产生内部编译器错误, code> int bar(std :: move(foo));



    由于这种巨大的行为差异,留下这个问题,虽然它的一部分可以通过减少到 int bar(std :: move(foo)); 来回答。






    *)NUC:Not universal compilable

    解决方案

    更新2 bug 已在r191150的Clang中修复。 GCC拒绝该代码并附上适当的错误信息。






    更新:一个href =http://llvm.org/bugs/show_bug.cgi?id=17295 =noreferrer> bug报告。在我的机器上使用clang ++ 3.4(trunk 191037)的代码如下:

      #include< iostream> 
    #include< memory>

    int main()
    {
    std :: unique_ptr< int> u_ptr(new int(42));

    std :: cout<< u_ptr.get()=<< u_ptr.get()<<的std :: ENDL;
    std :: cout<< * u_ptr =<< * u_ptr<<的std :: ENDL;

    auto s_ptr = std :: make_shared< int>(std :: move(u_ptr));

    std :: cout<< 移动后<<的std :: ENDL;

    std :: cout<< u_ptr.get()=<< u_ptr.get()<<的std :: ENDL;
    std :: cout<< * u_ptr =<< * u_ptr<<的std :: ENDL;
    std :: cout<< s_ptr.get()=<< s_ptr.get()<<的std :: ENDL;
    std :: cout<< * s​​_ptr =<< * s_ptr<<的std :: ENDL;

    code
    $ b $ p
    $ b

    打印此:

    <
    u_ptr.get()= 0x16fa010
    * u_ptr = 0x16fa010
    * u_ptr = 42
    移动
    之后,pre> u_ptr.get 42
    s_ptr.get()= 0x16fa048
    * s_ptr = 1

    你可以看到, unique_ptr 还没有被移出。标准的保证 ,它在被移出后应该为空。 shared_ptr 指向一个错误的值。



    奇怪的是,它没有警告就编译,valgrind不会'吨报告任何问题,没有泄漏,没有堆腐败。奇怪。



    如果我使用 shared_ptr 创建 s_ptr code> ctor将右值引用到 unique_ptr 而不是 make_shared

      #include< iostream> 
    #include< memory>

    int main()
    {
    std :: unique_ptr< int> u_ptr(new int(42));

    std :: cout<< u_ptr.get()=<< u_ptr.get()<<的std :: ENDL;
    std :: cout<< * u_ptr =<< * u_ptr<<的std :: ENDL;

    std :: shared_ptr< int> s_ptr {的std ::移动(u_ptr)};

    std :: cout<< 移动后<<的std :: ENDL;

    std :: cout<< u_ptr.get()=<< u_ptr.get()<<的std :: ENDL;
    // std :: cout<< * u_ptr =<< * u_ptr<<的std :: ENDL; //< - 会给出段错误
    std :: cout<< s_ptr.get()=<< s_ptr.get()<<的std :: ENDL;
    std :: cout<< * s​​_ptr =<< * s_ptr<<的std :: ENDL;

    $ / code $ / pre
    $ b $ p



    < pre $ get $ b $ u_ptr.get()= 0
    s_ptr.get()= 0x5a06040
    * u_ptr = 42
    ()= 0x5a06040
    * s_ptr = 42

    正如你所见, u_ptr 为空,并且 s_ptr 指向正确的值。这是正确的行为。






    (原始答案。)



    As Simple指出:除非Foo有一个构造函数接受std :: unique_ptr,否则它不应该编译。



    为了扩展它,有一点: make_shared 将其参数转发给T的构造函数。如果T没有任何可以接受 unique_ptr< T&&& 的ctor,这是一个编译错误。



    但是,修复此代码并获得所需内容很简单(在线演示): p>

      #include< memory> 
    使用namespace std;

    class widget {};

    int main(){

    unique_ptr< widget> uptr {新部件};

    shared_ptr< widget>特征码指针(的std ::移动(uptr));

    $ / code>

    关键是: make_shared 是错误的。 shared_ptr 有一个接受 unique_ptr 的ctor,请参阅(13)在 shared_ptr


    In a piece of code I reviewed lately, which compiled fine with g++-4.6, I encountered a strange try to create a std::shared_ptr from std::unique_ptr:

    std::unique_ptr<Foo> foo...
    std::make_shared<Foo>(std::move(foo));
    

    This seems rather odd to me. This should be std::shared_ptr<Foo>(std::move(foo)); afaik, though I'm not perfectly familiar with moves (and I know std::move is only a cast, nothing get's moved).

    Checking with different compilers on this SSC(NUC*)E

    #include <memory>
    
    int main()
    {
       std::unique_ptr<int> foo(new int);
       std::make_shared<int>(std::move(foo));
    }
    

    Results of compilation:

    • g++-4.4.7 gives compilation error
    • g++-4.6.4 compiles without any error
    • g++-4.7.3 gives internal compiler error
    • g++-4.8.1 gives compilation error
    • clang++-3.2.1 compiles without any error

    So the question is: which compiler is right in terms of the standard? Does the standard require this to be an invalid statement, a valid statement or is this simply undefined?

    Addition

    We've agreed on that some of these compilers, such as clang++ and g++-4.6.4, permit the conversion while they shouldn't. However with g++-4.7.3 (which produces an internal compiler error on std::make_shared<Foo>(std::move(foo));), correctly rejects int bar(std::move(foo));

    Because of this huge difference in behavior, I'm leaving the question as it is, although part of it would be answerable with the reduction to int bar(std::move(foo));.


    *) NUC: Not universally compilable

    解决方案

    UPDATE 2: This bug has been fixed in Clang in r191150. GCC rejects the code with a proper error message.


    UPDATE: I have submitted a bug report. The following code on my machine with clang++ 3.4 (trunk 191037)

    #include <iostream>
    #include <memory>
    
    int main()
    {
       std::unique_ptr<int> u_ptr(new int(42));
    
       std::cout << " u_ptr.get() = " <<  u_ptr.get() << std::endl;
       std::cout << "*u_ptr       = " << *u_ptr       << std::endl;
    
       auto s_ptr = std::make_shared<int>(std::move(u_ptr));
    
       std::cout << "After move" << std::endl;
    
       std::cout << " u_ptr.get() = " <<  u_ptr.get() << std::endl;
       std::cout << "*u_ptr       = " << *u_ptr       << std::endl;
       std::cout << " s_ptr.get() = " <<  s_ptr.get() << std::endl;
       std::cout << "*s_ptr       = " << *s_ptr       << std::endl;
    }
    

    prints this:

     u_ptr.get() = 0x16fa010
    *u_ptr       = 42
    After move
     u_ptr.get() = 0x16fa010
    *u_ptr       = 42
     s_ptr.get() = 0x16fa048
    *s_ptr       = 1
    

    As you can see, the unique_ptr hasn't been moved from. The standard guarantees that it should be null after it has been moved from. The shared_ptr points to a wrong value.

    The weird thing is that it compiles without a warning and valgrind doesn't report any issues, no leak, no heap corruption. Weird.

    The proper behavior is shown if I create s_ptr with the shared_ptr ctor taking an rvalue ref to a unique_ptr instead of make_shared:

    #include <iostream>
    #include <memory>
    
    int main()
    {
       std::unique_ptr<int> u_ptr(new int(42));
    
       std::cout << " u_ptr.get() = " <<  u_ptr.get() << std::endl;
       std::cout << "*u_ptr       = " << *u_ptr       << std::endl;
    
       std::shared_ptr<int> s_ptr{std::move(u_ptr)};
    
       std::cout << "After move" << std::endl;
    
       std::cout << " u_ptr.get() = " <<  u_ptr.get() << std::endl;
       //std::cout << "*u_ptr       = " << *u_ptr       << std::endl; // <-- would give a segfault
       std::cout << " s_ptr.get() = " <<  s_ptr.get() << std::endl;
       std::cout << "*s_ptr       = " << *s_ptr       << std::endl;
    }
    

    It prints:

     u_ptr.get() = 0x5a06040
    *u_ptr       = 42
    After move
     u_ptr.get() = 0
     s_ptr.get() = 0x5a06040
    *s_ptr       = 42
    

    As you see, u_ptr is null after the move as required by the standard and s_ptr points to the correct value. This is the correct behavior.


    (The original answer.)

    As Simple has pointed out: "Unless Foo has a constructor that takes a std::unique_ptr it shouldn't compile."

    To expand on it a little bit: make_shared forwards its arguments to T's constructor. If T doesn't have any ctor that could accept that unique_ptr<T>&& it is a compile error.

    However, it is easy to fix this code and get what you want (online demo):

    #include <memory>
    using namespace std;
    
    class widget { };
    
    int main() {
    
        unique_ptr<widget> uptr{new widget};
    
        shared_ptr<widget> sptr(std::move(uptr));
    }
    

    The point is: make_shared is the wrong thing to use in this situation. shared_ptr has a ctor that accepts an unique_ptr<Y,Deleter>&&, see (13) at the ctors of shared_ptr.

    这篇关于从unique_ptr创建一个shared_ptr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆