std::move 和 std::shared_ptr 参数按值传递

std::move and std::shared_ptr argument passed by value

提问人:cppdev 提问时间:9/14/2023 更新时间:9/14/2023 访问量:120

问:

请考虑以下代码:

#include <iostream>
#include <memory>

class Test
{
    public:
    Test(int t) : t(t) {}
    
    int t;
};

void test(std::shared_ptr<Test> t)
{
    std::cout << t.use_count() << std::endl;
}

int main()
{
    auto t = std::make_shared<Test>(1);
    test(std::move(t)); //(1)
    test(std::make_shared<Test>(2)); //(2)
}

问题:

  1. 在情况 (1) 中执行什么 ctor - 复制或移动?
  2. 如果 (2) 创建了 time,则执行 copy ctor 以在 中创建,然后销毁 temper。这是对的吗?tvoid test(std::shared_ptr<Test> t)
C++ 共享 PTR 移动语义

评论

1赞 Alan Birtles 9/14/2023
这两种情况都使用 Move 构造函数(尽管在第二种情况下可能会省略它): godbolt.org/z/bf1ohrvxW
1赞 Some programmer dude 9/14/2023
需要注意的是,移动(在这两种情况下)和临时(在情况 2 中)是对象本身,而不是它包装指针的对象。在每种情况下,只有一个对象,不会移动或复制。std::shared_ptr<Test>TestTest
0赞 user4581301 9/14/2023
通过检查 main 末尾的 来确认 1。tuse_count

答:

4赞 Ted Lyngmo 9/14/2023 #1

您的示例中总共创建了 3 个:std::shared_ptr<Test>

  1. auto t = std::make_shared<Test>(1);

  2. test(std::move(t));- 接收输入是移动构造的。ttest()

  3. test(std::make_shared<Test>(2));- 接收是由 创建的接收。它是同一个对象,因为自 C++ 17 以来强制复制/移动省略tmake_shared()

    在 C++ 17 之前,理论上你可以得到多达 5 个实例化 - 但由于这种省略在以前的版本中是允许的(但不是强制性的),所以在这些版本中你很可能也只能得到 3 个。使用这些早期版本之一时,您可以在某些编译器(例如/)中使用 关闭此优化。在 C++ 17 及更高版本中,省略是必需的,因此无法关闭。g++clang++-fno-elide-constructors


这是一个演示,它不使用,而是使用一个名为的测试类,以便您可以跟踪每个实例化。请注意,只有一个值为 ,它对应于您的调用。shared_ptrfoofoo2test(std::make_shared<Test>(2));

评论

0赞 cppdev 9/14/2023
您的意思是,如果与例如C++11编译器一起使用,那么在我的示例中,如果(2)将使用移动ctor创建接收?-fno-elide-constructorst
0赞 Ted Lyngmo 9/14/2023
@cppdev 是的(例如,gcc 有 no-elide-constructors 而 clang 没有),并注意当使用该选项时 () 也会导致移动构造,因此总共有 5 个实例。auto t = std::make_shared<Test>(1);auto t = make_foo(1);