3

1)

template<typename T, typename Arg> 
  shared_ptr<T> factory(Arg arg)
  { 
    return shared_ptr<T>(new T(arg));
  } 

2)

template<typename T, typename Arg> 
  shared_ptr<T> factory(Arg& arg)
  { 
    return shared_ptr<T>(new T(arg));
  } 

3)

template<typename T, typename Arg> 
  shared_ptr<T> factory(Arg const & arg)
  { 
    return shared_ptr<T>(new T(arg));
  } 

*) 为什么 3 号比 1 号和 2 号更受欢迎?

*) 如果调用 factory(41),为什么要在右值上调用?

*)# 定义 BOOST_ASIO_MOVE_ARG(type) type&&. 在这种情况下 && 是什么?

4

2 回答 2

10

实际上,方法#3并不比 1 和 2 好。这完全取决于T' 的构造函数。

执行此操作的一种标准方法是使用您提到的右值引用。&&

所以,一个更好的工厂应该是这样的:(这实际上是完美的转发

template<typename T, typename Arg> 
std::shared_ptr<T> factory(Arg && arg)
{
    return std::shared_ptr<T>(new T (std::forward<Arg>(arg)));
}

由于 C++ 的引用折叠规则,这个函数可以接受(和转发)右值引用和左值引用,即,如果你传递一个右值,它会忠实地将该右值转发给T的构造函数,如果你给它一个左值,两种引用Something & && arg

我想我在这里涵盖了你的问题,但要明确回答,

  • #3不是这里的首选方法。甚至在 C++11 之前,您可能都想要函数的重载const&&重载factory。版本更好,const&它实际上会接受临时值,但如果你的底层T类型有一个接受非常量引用的构造函数,那么你会得到一个编译错误,因为 aconst&没有隐式转换为 a &
  • 因为您不能获取文字的地址41(这在技术上并不是 100% 正确,但我认为以这种方式考虑左值和右值是可以的。)
  • 它表示一个rvalue reference. 您需要阅读相关内容;这里不适合解释,而且已经有几个很棒的,只需谷歌搜索即可!

更新:正如评论中切线提到的那样,使用make_shared可能比shared_ptr使用对齐的new指针构造 a 更好。make_shared可以通过将控制块(包括引用计数)与对象本身一起分配来获得更好的效率,这将在访问引用计数器和对象时提供更好的缓存局部性,并且还可以节省一次内存分配。即使实现没有任何优化,也不会比上面的版本差。所以std::make_shared尽可能使用!这就是你在这里的做法:

template<typename T, typename Arg> 
std::shared_ptr<T> factory (Arg && arg)
{
    return std::make_shared<T>(std::forward<Arg>(arg));
}
于 2013-08-31T02:13:01.910 回答
1

*) 为什么 3 号比 1 号和 2 号更受欢迎?

(1) 如果Arg不可复制,则无法使用。(2) 不允许您传递右值,如factory<int>(42);

请注意,这三个示例都没有涉及完美转发。我不确定你的问题是指什么。

*) 如果调用 factory(41),为什么要在右值上调用?

我不确定我是否理解这个问题。41根据定义是一个右值。

*)# 定义 BOOST_ASIO_MOVE_ARG(type) type&&. 在这种情况下 && 是什么?

type&&是对 的右值引用type

于 2013-08-31T02:12:05.070 回答