如何以更好的性能传递和共享shared_ptr所有权?

时间:2018-03-27 21:49:06

标签: c++ c++11 shared-ptr

例如

<div>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</div>

通常哪个选项更好?

我在Visual Studio 2017上做了基准测试。在我测试的所有情况下,选项2都给了我最好的性能。在某些情况下,选项3具有与选项2类似的性能,但有些情况更糟。谢谢!

1 个答案:

答案 0 :(得分:0)

在您的情况下,选项2是最好的情况。您可能希望移动指向该类的指针,因此当您不再需要它时,您不需要一次又一次地增加和减少引用计数器:

{
    shared_ptr<int> ptr = std::make_shared<int>(42);

    A a;
    a.setI_2(std::move(ptr)); // I no longer need ptr, so I can move it
};

指针移动到参数列表,ptr为null /参数初始化为r值引用,引用ptr,因此ptr变为空。然后将它从参数列表移动到成员,参数为null。你看,没有(需要一个)副本,这意味着更改了引用计数器。

我更喜欢T const&仅用于仅从引用读取且不用于初始化另一个变量的函数。如果在示例中使用了带引用的第三个选项,则需要复制指针,因为setI_3的主体在赋值语句中有一个副本(不移动)。

第一个选项显然是最差的,因为指针被多次复制。

当您将shared_ptrunique_ptr交换时,编译器强制您尽可能使用最快的方法 - 移动。

我会添加第四个选项:

// Option 4
void setI_4(shared_ptr<int>&& i) { m_i = move(i); }

请注意,即使i是一个r值引用,它在代码中使用时也不是r值引用,因此在没有移动时会被复制;

第四个选项只与第二个选项不同,传递的参数总是需要是一个r值引用,而在第二个选项中,i本身就是一个指针变量,在第四个选项中i是一个引用(函数体可以执行任何操作,但它存在于函数之外(std :: move允许执行此操作))。参数变量是从调用者的参数元组中的表达式构造的,shared_ptr的构造函数自动复制指针(这意味着参考计数器增加),如果它不是r值 - 参考

调用setI_2的工作原理如下:

{
    shared_ptr<int> ptr = std::make_shared<int>(42);
    /// ptr owns 42
    A a;
    {   // a.setI_2(std::move(ptr));
        // initializing the parameter
        shared_ptr<int> i{std::move(ptr)};
        // now i owns 42 and ptr no longer owns it and points to null
        {   // the body of the function
            a.m_i = std::move(i);
            // now a.m_i owns 42 and i no longer owns it and points to null
        };
    };
};