Search code examples
c++move-semanticsc++23

Insert multiple non-copyable values to `std::vector`


Inserting N values to an std::vector one-by-one is inefficient. So, you can insert them all-at-once.

My problem is that my values are not copy-constructible.

So, the question is how can I make the following code to work without inserting one-by-one the values.

Is there a mapping process which takes one std::string and one DOMObject* and give a Field? Is there a move semantics feeding to std::vector?

#include <span>
#include <concepts>
#include <iterator>
#include <iostream>
#include <string>
#include <memory>
#include <vector>

using namespace std;


class DOMObject {};


struct Field
{
    std::string key;
    std::unique_ptr<DOMObject> value;
};


std::vector<Field> fields;


void insert_many(size_t pos, const std::span<string> &keys, const std::span<DOMObject*> &values)
{
    fields.insert(fields.begin() + pos, values.size(), {});  // Copy construction is not allowed
    for (size_t i = 0; i < values.size(); ++i)
    {
        fields[pos + i].key = std::move(keys[i]);
        fields[pos + i].value.reset(values[i]);
    }
}


int main()
{
}

Solution

  • Like this : combination of insert and make_move_iterator

    #include <string>
    #include <memory>
    #include <span>
    #include <vector>
    #include <iostream>
    
    class DOMObject 
    {
    };
    
    struct Field
    {
        Field() { std::cout << "Field()\n"; }
        Field(const Field&) = delete;
        Field& operator=(const Field&) = delete;
        Field(Field&&) noexcept { std::cout << "Field(Field&&)\n"; }
        Field& operator=(Field&&) noexcept { std::cout << "Field =Field&&\n"; return *this; }
        ~Field() { std::cout << "~Field()\n"; }
    
        std::string key;
        std::unique_ptr<DOMObject> value;
    };
    
    void insert_many(std::vector<Field>& fields, std::span<Field> new_fields)
    {
        std::cout << "inserting\n";
        fields.insert(fields.end(), std::make_move_iterator(new_fields.begin()), std::make_move_iterator(new_fields.end()));
    }
    
    int main()
    {
        {
        std::vector<Field> fields(3);
        std::vector<Field> new_fields(2);
    
        fields[0].key = "one";
        fields[1].key = "two";
        fields[2].key = "three";
        new_fields[0].key = "four";
        new_fields[1].key = "five";
        
        insert_many(fields,new_fields);
        for(auto& value : fields)
        {
            std::cout << value.key << "\n";
        }
        } //extra scope for deletion of vectors
    }