关于时间成本,更贵的是:移动还是覆盖? C ++ 11

时间:2013-03-11 14:44:24

标签: c++ c++11 move dynamic-memory-allocation

让我们来看看我有一堆“未使用”的动态对象。每次我需要一个新对象时,我都会使用其中一个“未使用”的对象作为新请求的占位符。类似的东西:

template<typename T>
class my_list
{
public:
   template<typename... Args>
   T* newObject(Args&&... args)
   {
       if (unused.empty())
          return new T(forward<Args>(args)...);
       else {
          auto* newbie = unused.top();
          unused.pop();

          newbie = new (newbie) T(forward<Args>(args)...); // l. X

          return newbie;
       }
   }

private:
   stack<T*> unused;

};

问题是,在第X行,什么是更有效,书面的句子,或:

*newbie = std::move(T(forward<Args>(args)...));

这意味着,两者的时间效率更高,调用new newbie作为地址(避免请求新内存)或只是移动新的临时对象覆盖原始

2 个答案:

答案 0 :(得分:3)

这是另一个可行的选择。它的优势在于,虽然C ++ 11仍然是完美转发所必需的,但它可以使用尚未更新的库代码来实现移动构造和赋值。

T(forward<Args>(args)...).swap(*newbie);

此外,您的移动分配调用已经有一个临时对象,无需明确地使其移动。

*newbie = T(forward<Args>(args)...);

这些中的任何一个都会比“先破坏,然后构建就地”方法更容易提供异常安全。

答案 1 :(得分:2)

move是不必要的,因为构造函数调用会创建一个prvalue临时值。你的问题归结为哪个更有效:

newbie->~T();
new (newbie) T(std::forward<Args>(args)...);

*newbie = T(std::forward<Args>(args)...);

假设T有一个正确编写的移动赋值运算符,则可能没有什么区别(如果有的话);在副作用方面,T的析构函数在第一种情况下在构造函数之前调用,在第二种情况之后调用,但是没有理由相信这会比另一种情况更多地影响性能。后者可能会产生更原始的值副本,但任何体面的优化编译器都会消除它们。

如果没有性能测试表明前者显着提高了性能,那么您应该更喜欢后者,因为它更易读,更容易使异常安全。