Drew
Drew

Reputation: 13398

Why doesn't this use of emplace_back with deleted copy constructor work?

I have a type that I have deleted the copy constructor from, and I would like to have a vector of this type, so I need to create all the elements via emplace_back. But, emplace_back seems to require a copy constructor, as the compiler gives a warning about not being able to instantiate emplace_back because the copy constructor has been deleted. Why does it need a copy constructor? I thought the whole point of emplace_back was to build the vector without copying anything. Can I even have a vector of objects that don't have a copy constructor?

class MyType {
public:
    MyType(std::array<double, 6> a) {}
    MyType(const MyType& that) = delete;
};

int main() {
    std::vector<MyType> v;
    std::array<double, 6> a = {1,2,3,4,5,6};
    v.emplace_back(a);
}

Compiler is clang/llvm.

Upvotes: 22

Views: 8086

Answers (3)

BoBTFish
BoBTFish

Reputation: 19767

When the vector's internal storage grows, it will need to move the elements from the old storage to the new. By deleting the copy constructor, you also prevent it generating the default move constructor.

Upvotes: 35

Humam Helfawi
Humam Helfawi

Reputation: 20264

If you try to run this code:

// Example program
#include <iostream>
#include <string>
#include <array>
#include <vector>
class MyType {
public:
    MyType(std::array<double, 6> a) {
        std::cout<< "constructed from array\n";
        }
    MyType(const MyType& that){
          std::cout<< "copy\n";
    }

    MyType(MyType&& that){
          std::cout<< "move\n";
    }
};

int main() {
    std::vector<MyType> v;
    std::array<double, 6> a = {1,2,3,4,5,6};
    v.emplace_back(a);
}

You will get the following result:

constructed from array

Live Demo

It is clear that just the constructor from std::Array is called. So, no need for copy constructor. But in the same time if you deleted the copy constructor, the compiler will raise an error (at least on two compilers I tried first second ). I think that some compilers will check for the existence of copy constructor when using emplace_back even if it is not necessary in this practical case while others won't. I do not know what is standard here (which compiler is right or wrong).

Upvotes: 2

bashrc
bashrc

Reputation: 4835

To be able to call emplace_back, your type should either be EmplaceConstructible or MoveInsertible . You need to give a move constructor to your class if you have deleted the copy constructor. (Check this for requirements of emplace_back)

 MyType(MyType &&a) {/*code*/} //move constructor

Upvotes: 12

Related Questions