简体   繁体   English

std::vector emplace_back 实现

[英]std::vector emplace_back implementation

The push_back function that I implemented:我实现的 push_back function:

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

And the emplace_back function:还有 emplace_back function:

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

Do you see any problem with this?你觉得这有什么问题吗? If yes then could you please tell me如果是,那么你能告诉我吗

Also, please let me know how does this work?另外,请让我知道这是如何工作的?

Please note: the emplace_back is not my implementation, I took it from other questions as I was looking for a way to implement my own emplace_back.请注意:emplace_back 不是我的实现,我从其他问题中获取它,因为我正在寻找一种方法来实现我自己的 emplace_back。

Do you see any problem with this?你觉得这有什么问题吗?

You aren't really emplacing with this.你并没有真正接受这个。 There's still an assignment.还有一个任务。

std::vector<T> doesn't allocate an array of T . std::vector<T>分配T数组。 It allocates raw memory with the size and alignment of an array of T , and then instantiates objects in that raw memory.它使用T数组的大小和 alignment 分配原始 memory ,然后在该原始 memory 中实例化对象。

With that in mind, you should probably implement push_back in terms of emplace_back , rather than the other way around.考虑到这一点,您可能应该根据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)); }
}

Also, please let me know how does this work?另外,请让我知道这是如何工作的?

template <typename... Args> allows zero or more types to match this template, and then T(std::forward<Args>(args)...) is constructing a T with those arguments, "perfectly forwarding" them, ie rvalues are passed as rvalues and lvalues as lvalues. template <typename... Args>允许零个或多个类型与此模板匹配,然后T(std::forward<Args>(args)...)正在用那些 arguments 构造一个T“完美转发”它们,即右值作为右值传递,左值作为左值传递。

Nb because std::vector doesn't new[] , you cannot implement something that behaves exactly like std::vector before C++ 20, because it has to be able to return a pointer to an array of T from data without constructing an array of T .注意,因为std::vector不是new[] ,所以您不能在 C++ 20 之前实现与std::vector完全相同的东西,因为它必须能够在不构造数组的情况下从data中返回指向T数组的指针的T

The point of emplace_back is to construct an object in place. emplace_back的重点是在原地构造一个 object。 Your implementation constructs an object then copies it to my_vec .您的实现构造一个 object 然后将其复制到my_vec

Your implementation will not work with types that are not copyable.您的实现不适用于不可复制的类型。 Eg this won't compile:例如,这不会编译:

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

Changing push_back to take it's argument via rvalue reference will fix the issue:更改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)...));
}

I think however that most standard library implementations are implemented using emplace_back as the lowest level function:然而,我认为大多数标准库实现都是使用emplace_back作为最低级别的 function 实现的:

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++;
}

This then makes it easier to implement the push_back overload that copies the values:这样就更容易实现复制值的push_back重载:

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

Note that this implementation is using move assignment which is still not quite the intention of emplace_back which requires constructing an object in place using placement new on uninitialised memory but assuming my_vec is an array of objects or similar its the best you can do (without fully implementing the semantics of std::vector which is fairly complex).请注意,此实现正在使用移动分配,这仍然不是emplace_back的意图,它需要在未初始化的 memory 上使用放置新的位置构造一个 object 但假设my_vec是一个对象数组或类似的最好的你可以做的(没有完全实现std::vector的语义相当复杂)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM