gpt4 book ai didi

c++ - std::make_shared 在 VS2012 中进行两次构造函数调用

转载 作者:太空狗 更新时间:2023-10-29 19:52:27 27 4
gpt4 key购买 nike

我写了一段简单的代码来试用 C++11 的 make_shared。我不明白为什么当我打电话时:

std::shared_ptr<MyClass> x = std::make_shared<MyClass>(MyClass());

调用默认构造函数并调用移动构造函数。乍一看这似乎很好,因为移动构造函数不会创建拷贝。但是如果我注释掉 MyClass 的移动构造函数的实现,它将调用默认构造函数,然后是复制构造函数,这似乎违背了 make_shared 的目的。

#include <iostream>
#include <memory>

//-----------------------------------------------------------

class MyClass {

public:

// default constructor
MyClass() :
_data(0.0)
{
_data = (float)3.14;

std::cout << "MyClass::default constructor - data=" << _data << " ; class=" << this << std::endl;
};

// copy constructor
MyClass(const MyClass& input)
{
_data = input._data;

std::cout << "MyClass::copy constructor - data=" << _data << " ; class=" << this << std::endl;
};

// move constructor
MyClass(MyClass&& other)
{
std::cout << "MyClass::move constructor(before) - data=" << _data << " ; class=" << this << std::endl;

_swap(*this, other);

std::cout << "MyClass::move constructor(after) - data=" << _data << " ; class=" << this << std::endl;
};

// destructor
~MyClass()
{
std::cout << "MyClass::destructor - data=" << _data << " ; class=" << this << std::endl;
};

private:

// swap
void MyClass::_swap(MyClass& X, MyClass& Y)
{
std::swap(X._data, Y._data);
}

// members
float _data;

};

//-----------------------------------------------------------

int main()
{
std::shared_ptr<MyClass> x = std::make_shared<MyClass>(MyClass());

std::cout << std::endl << "Address for x: " << x << std::endl;

std::cout << std::endl << "Press Enter to exit." << std::endl;
std::cin.ignore();
return 0;
}

以上代码的输出是:

MyClass::default constructor - data=3.14 ; class=000000000019F860
MyClass::move constructor(before) - data=0 ; class=00000000003C3440
MyClass::move constructor(after) - data=3.14 ; class=00000000003C3440
MyClass::destructor - data=0 ; class=000000000019F860

Address for x: 00000000003C3440

Press Enter to exit.

MyClass::destructor - data=3.14 ; class=00000000003C3440

如果我注释掉移动构造函数,输出是这样的:

MyClass::default constructor - data=3.14 ; class=000000000016FA00
MyClass::copy constructor - data=3.14 ; class=00000000001B3440
MyClass::destructor - data=3.14 ; class=000000000016FA00

Address for x: 00000000001B3440

Press Enter to exit.

MyClass::destructor - data=3.14 ; class=00000000001B3440

也许我对 make_shared 功能的理解有误。谁能向我解释为什么会这样?

谢谢。

最佳答案

当你打电话时:

std::shared_ptr<MyClass> x = std::make_shared<MyClass>(MyClass());

是这样的:

  1. 创建内部 MyClass() 实例(第一个构造函数调用 - 默认调用)。
  2. 内部 MyClass() 是临时的。
  3. 现在,make_shared 将您的临时 MyClass 完美转发到 MyClass移动构造函数,因为MyClass 声明一个,临时对象可以通过右值引用 MyClass&& 进行绑定(bind)。 (第二个构造函数调用 - 移动构造函数)。

现在,当您删除移动构造函数时,会发生以下情况:

  1. 创建内部 MyClass() 实例(第一个构造函数调用 - 默认调用)。
  2. 内部 MyClass() 是临时的。
  3. 现在,make_shared 完美转发您的临时 MyClass,但是因为 MyClass 没有移动构造函数,临时文件由复制构造函数的 const MyClass& 引用,因此调用复制构造函数(第二个构造函数调用 - 复制构造函数)。

也就是说,您传递给 std::make_shared 的参数实际上是构造函数的参数,而不是实例本身。因此你应该写:

std::shared_ptr<MyClass> x = std::make_shared<MyClass>();

例如,如果您有一个具有以下签名的 MyClass 构造函数:

MyClass(int x, float f, std::unique_ptr<int> p);

然后你会说:

std::shared_ptr<MyClass> x
= std::make_shared<MyClass>(123, 3.14f, std::make_unique<int>(5));

make_shared 保证这些参数将完美转发MyClass 构造函数。

您可以将 std::make_shared 辅助函数想象成如下所示:

template <typename T, typename... Args>
auto make_shared(Args&&... args) -> std::shared_ptr<T>
{
return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
}

注意:实际上 make_shared 还在连续的内存块中为引用计数器分配空间,绑定(bind)析构函数,并执行其他操作。上面的代码片段只是一个示例,用于说明参数本身会发生什么。

关于c++ - std::make_shared 在 VS2012 中进行两次构造函数调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25595950/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com