【问题标题】:what's the optimum way to implement push_back without overhead在没有开销的情况下实现 push_back 的最佳方法是什么
【发布时间】:2020-07-14 08:58:28
【问题描述】:

我正在尝试实现一个队列,您可以在其中将要添加到队列中的对象传递给它。

struct Node {
    T data;
    Node *next, *prev;
};    
// Push data to the back of the list.
template <class T> T& CircularQueue<T>::push_back(const T&& new_data)
{
    Node* new_node = new Node();
    new_node->data = std::move(new_data);
    link_node(new_node, m_head);
    return new_node->data;
}

我目前的方法的问题是开销太大(因为我来自 C,这些事情让我很困扰)。例如图像,我将从 MyClass 添加一个对象:

CircularQueue<MyClass> list;
list.push_back(MyClass(arg1, arg2));

第一个问题是 MyClass 需要有一个不带参数的构造函数才能在Node* new_node = new Node(); 中使用,因为创建 Node 结构将调用其中对象的构造函数,即 MyClass。我用 std::vector 试过了,它不需要这个。

第二个问题是开销太大,list.push_back(MyClass(arg1, arg2)); 将在堆栈中创建一个右值对象然后发送到push_back,然后它在堆中创建一个新对象(没有参数列表)然后移动其所有成员使用移动分配到新对象,有没有更快的解决方案?

【问题讨论】:

  • const T&amp;&amp; new_data 只会把它变成一个副本。不会有任何动作
  • 不,不会。您不能从 const 对象移动。这就是为什么右值引用永远不是const
  • 不,不会的。 const 完全否定移动语义
  • 我看到的第一个也是最大的问题是你为你推送的每个元素分配内存
  • @t.niese 我认为这有帮助,我的意思是我们可以直接使用移动​​构造函数,而不是创建一个对象然后使用移动赋值。

标签: c++ performance circular-list


【解决方案1】:

你可以 emplace_back 你的节点

template <class T> 
class CircularQueue {
    template<typename... U>
    T &emplace_back(U&&... u)
    {
       Node *new_node = new Node{{std::forward<U>(u)...}}; // <data is created here
        // link_node(new_node, m_head);
       return new_node->data;
    }
};
void foo() {
    CircularQueue<Data> x;
    // Do not create a Data, pass the parameters you need to create
    x.emplace_back(10, 20);
    // If you actually need to, you can of course copy or move an existing Data
    Data y(20, 30);
    x.emplace_back(y); // copies y
    x.emplace_back(std::move(y)); // moves y
}

https://godbolt.org/z/z68q77

【讨论】:

  • 我认为这是最好的解决方案,尽管您发布的编译器资源管理器链接中的代码已被优化掉。
  • new Node{{std::forward&lt;U&gt;(u)...}} 会以不可预知的方式与std::vector 等类一起使用。需要替换为new Node{T(std::forward&lt;U&gt;(u)...)}
猜你喜欢
  • 2023-03-25
  • 1970-01-01
  • 2021-08-27
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-08
  • 1970-01-01
相关资源
最近更新 更多