gpt4 book ai didi

c++ - 从 unique_ptr 创建 shared_ptr

转载 作者:IT老高 更新时间:2023-10-28 14:01:33 26 4
gpt4 key购买 nike

在我最近查看的一段代码中,它用 g++-4.6 编译得很好,我遇到一个奇怪的尝试创建一个std::shared_ptr来自 std::unique_ptr :

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

这对我来说似乎很奇怪。这应该是 std::shared_ptr<Foo>(std::move(foo)); afaik,虽然我对 Action 并不十分熟悉(而且我知道 std::move 只是一个类型转换,没有任何 Action )。

在此 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)); 上产生内部编译器错误),正确拒绝 int bar(std::move(foo));

由于行为上的巨大差异,我将问题原样保留,尽管部分问题可以通过减少到 int bar(std::move(foo)); 来回答。 .


*) NUC:不可普遍编译

最佳答案

更新 2: 这个 bug已在 r191150 的 Clang 中修复。 GCC 拒绝代码并显示正确的错误消息。


更新:我已经提交了 bug report .以下代码在我的机器上使用 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;
}

打印这个:

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

如您所见,unique_ptr没有被搬离。标准保证它在被移出后应该为空。 shared_ptr指向错误的值。

奇怪的是它编译时没有警告,valgrind 没有报告任何问题,没有泄漏,没有堆损坏。很奇怪。

如果我创建 s_ptr,则会显示正确的行为与 shared_ptr 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::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;
}

打印出来:

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

如您所见,u_ptr按照标准和 s_ptr 的要求在移动后为空指向正确的值。这是正确的行为。


(原来的答案。)

As Simple has pointed out :“除非 Foo 有一个构造函数,它采用 std::unique_ptr 它不应该编译。”

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

但是,很容易修复此代码并得到您想要的 (online demo):

#include <memory>
using namespace std;

class widget { };

int main() {

unique_ptr<widget> uptr{new widget};

shared_ptr<widget> sptr(std::move(uptr));
}

重点是:make_shared在这种情况下使用是错误的。 shared_ptr有一个接受 unique_ptr<Y,Deleter>&& 的 ctor ,见 (13) at the ctors of shared_ptr .

关于c++ - 从 unique_ptr 创建 shared_ptr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18889843/

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