shared_ptr 初始化

3

成员被定义为

std::shared_ptr<std::array<std::string, 6> > exit_to;

这是指向其他数据共享的附加数据。 当尝试初始化指针“exit_to”时,正确的方式是

node_knot.exit_to = std::make_shared<std::array<std::string, 6> >();

但是它在另一个文件中,我想保持指针类型的一致性,类似于这样:

node_knot.exit_to = std::make_shared<decltype(*node_knot.exit_to)>();

但是无法编译:

 /usr/include/c++/4.6/bits/shared_ptr_base.h:798:54: error: '__p'
 declared as a pointer to a reference of type
 'std::array<std::basic_string<char>, 6> &'
         __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r, _Tp* __p)
                                                             ^ /usr/include/c++/4.6/bits/shared_ptr.h:93:31: note: in instantiation
 of template class
 'std::__shared_ptr<std::array<std::basic_string<char>, 6> &, 1>'
 requested here
     class shared_ptr : public __shared_ptr<_Tp>
                               ^ ../node_booker.h:757:20: note: in
 instantiation of template class
 'std::shared_ptr<std::array<std::basic_string<char>, 6> &>' requested
 here
                                                         n.exit_to = std::make_shared<decltype(*n.exit_to)>();

我使用的是Ubuntu 12.10操作系统,编译器是clang++ 3.2,并开启了--std=c++11选项。

2个回答

6

你需要从传递给make_shared的类型中移除引用。以下代码应该可以正常工作:

node_knot.exit_to = std::make_shared<std::remove_reference<decltype(*node_knot.exit_to)>::type>();

4
问题在于*exit_to类型是引用,你不能拥有指向引用的shared_ptr
你可以去掉引用,但是不要找到由operator*返回的类型并剥离它的引用,可能更容易的方法是询问shared_ptr包含的类型。
node_knot.exit_to = std::make_shared<decltype(node_knot.exit_to)::element_type>();

嵌套的element_type是由shared_ptr存储的类型。

另一种选择是在类中添加typedef并在需要时始终使用它:

typedef std::array<std::string, 6> string_array;
std::shared_ptr<string_array> exit_to;

// ... 

node_knot.exit_to = std::make_shared<Node::string_array>();

使用decltype相比之下,这种方式更易读。


我认为,构造函数 decltype(node_knot.exit_to)::element_type 打破了使用 decltype 的目的,因为您假定(或添加了)node_knot.exit_to 类型具有 element_type 成员的约束条件,这实际上对于大多数 STL 类型都不是真的。不过,您的第二个解决方案听起来更好。不过要注意的是,在 typedef 本身中包括类型名称似乎会降低 typedef 的价值。typedef 的一个优点是,您可以将 string_array 的基础容器类型更改为任何其他类型,而不必在代码中更改所有出现的情况。 - Ed Rowlett-Barbu
然而,将 _array 放在 string_array 中有点违背了这个目的,因为一旦基础类型更改,名称就不再反映类型。看看那个可怕的东西叫做匈牙利命名法,呸:http://en.wikipedia.org/wiki/Hungarian_notation - Ed Rowlett-Barbu
@Zadirion,使用make_shared不已经默认使用了shared_ptr吗?至于typedef,我总体上同意,但这取决于类型的要求。如果它可以是任何序列,那么在名称中放置“array”会产生误导作用,但如果它是具有某些类似字符串类型的连续元素的设计要求,则称其为“string_array”是可以的,即使您将其更改为vector<string>或仅为不同长度的数组,它仍然有效。如果没有更多上下文信息,就不能说名称应该更通用。 - Jonathan Wakely
非常抱歉,我忽略了std::make_shared将返回值分配回node_knot.exit_to本身而不是其他共享指针的事实,如果是这种情况,我的话就有意义了。 - Ed Rowlett-Barbu
关于“不知道更多上下文,您无法确定名称是否应该更为通用。” 说实话,过分具体比过于笼统并包容所有可能性要危险得多:P。 typedef std :: array <std :: string,6> string_container; 更好一点。 名称中仍然有“string”,但至少“string”可以是“std :: string”或“std :: wstring”或“CString”或其他内容。 不过这只是我的吹毛求疵。 回到主题,您的答案非常好,我已经给了赞。 我仍然会选择去掉引用,因为它是一种更普遍的方法。 但归根结底,这只是个人偏好问题。 - Ed Rowlett-Barbu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接