【问题标题】:std::vector emplace_back implementationstd::vector emplace_back 实现
【发布时间】:2021-06-09 09:08:52
【问题描述】:

我实现的 push_back 函数:

void push_back(T& num) {
    my_vec[index] = num;
    index++;
}

还有 emplace_back 函数:

template<class... Args>
void emplace_back(Args&&... args) {
    push_back(T(std::forward<Args>(args)...));
}

你觉得这有什么问题吗?如果是,请告诉我

另外,请告诉我这是如何工作的?

请注意:emplace_back 不是我的实现,我是从其他问题中获取的,因为我正在寻找一种方法来实现我自己的 emplace_back。

【问题讨论】:

  • 它没有达到emplace_back的目的,你要么需要让push_back使用可移动的值,要么让push_back调用emplace_back
  • emplace_back 的想法是在原始内存中就地构造一个元素。你只是在使用简单的分配,这不是emplace_back 应该做的,即使它是一个移动分配。
  • emplace_back 在placement new 中使用了一些东西,所以你的实现是错误的。
  • 这不是我的实现。我已经提到过。取自这里:stackoverflow.com/questions/58881357/…

标签: c++ vector


【解决方案1】:

你觉得这有什么问题吗?

你并没有真正接受这个。还有一个任务。

std::vector&lt;T&gt; 分配T 的数组。它使用T 数组的大小和对齐方式分配原始内存,然后在该原始内存中实例化对象。

考虑到这一点,您可能应该根据emplace_back 来实现push_back,而不是相反。

template <typename T>
class my_vector {
    T * start;
    std::size_t size;
    std::size_t capacity;

    void grow(); // Implementation of this is left as an exercise to the reader

public:
    template <typename... Args>
    reference emplace_back(Args&&... args) {
        if (size == capacity) grow();
        return *new (start + size++) T(std::forward<Args>(args)...);
    }

    reference push_back(const T & t) { return emplace_back(t); }
    reference push_back(T && t) { return emplace_back(std::move(t)); }
}

另外,请告诉我这是如何工作的?

template &lt;typename... Args&gt; 允许零个或多个类型匹配此模板,然后T(std::forward&lt;Args&gt;(args)...) 使用这些参数构造T"perfectly forwarding" 它们,即右值作为右值传递,左值作为左值传递。

注意因为std::vector 不是new[],所以在 C++ 20 之前,您不能实现与std::vector 类似的行为完全的东西,因为它必须能够返回指向T 数组的指针来自data 而不构造T 的数组。

【讨论】:

    【解决方案2】:

    emplace_back 的重点是在原地构造一个对象。您的实现构造一个对象,然后将其复制到my_vec

    您的实现不适用于不可复制的类型。例如。这不会编译:

    Vector<std::thread> v;
    v.emplace_back([](){});
    v.push_back(std::thread([](){}));
    

    更改 push_back 以通过右值引用获取它的参数将解决问题:

    void push_back(T&& num) {
        my_vec[index] = std::move(num);
        index++;
    }
    
    template<class... Args>
    void emplace_back(Args&&... args) {
        push_back(T(std::forward<Args>(args)...));
    }
    

    然而,我认为大多数标准库实现都是使用emplace_back 作为最低级别的函数来实现的:

    void push_back(T&& num) {
        emplace_back(std::move(num));
    }
    
    template<class... Args>
    void emplace_back(Args&&... args) {
        my_vec[index] = T(std::forward<Args>(args)...);
        index++;
    }
    

    这样可以更轻松地实现复制值的push_back 重载:

    void push_back(const T& num) {
        emplace_back(num);
    }
    

    请注意,此实现正在使用移动分配,这仍然不是 emplace_back 的意图,它需要在未初始化的内存上使用放置新的位置构造一个对象,但假设 my_vec 是一个对象数组或类似它最好的你可以这样做(没有完全实现 std::vector 的语义,这是相当复杂的)。

    【讨论】:

    • 非常感谢!
    猜你喜欢
    • 2017-01-12
    • 2015-01-15
    • 2017-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多