I took my first C++ class in 1990, long before your newfangled exceptions, STL and whatnot. Now I am writing a custom C++ container and I decided I would use this as an opportunity to learn some C++11 techniques and concepts, especially unique_ptr. Unfortunately I am having some trouble with the move semantics (I think) when inserting an element. Here is a very stripped down version of the code I am trying to get to compile:
#include <vector>
#include <memory>
struct Key {
int k_;
Key() : k_(0){};
explicit Key(int k) : k_(k){};
Key(const Key &o) : k_(o.k_) {}
Key(Key &&o) { k_ = std::move(o.k_); }
Key &operator=(const Key &o) {
k_ = o.k_;
return *this;
}
Key &operator=(Key &&o) {
k_ = std::move(o.k_);
return *this;
}
int get() const { return k_; }
};
template <class T> class CustomContainer {
public:
typedef std::pair<Key, std::unique_ptr<Key>> Record;
CustomContainer() {}
~CustomContainer(){};
bool insert(const Record &record) {
objects.emplace_back(std::move(record));
return true;
}
std::vector<Record> objects;
};
int main() {
CustomContainer<Key> q;
q.insert(CustomContainer<Key>::Record(Key(1), std::unique_ptr<Key>(new Key(1))));
}
I am inserting a pointer to a Key object to keep the code simple. In my actual application, Key is a little more complicated, T is not Key, and the Custom container has many more member functions, but this is enough to highlight the problem. When I just have a unique_ptr object in the vector, everything appears to work just fine. As soon as I add the pair, I get:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/ext/new_allocator.h:120:23: error: call to
implicitly-deleted copy constructor of 'std::pair<Key, std::unique_ptr<Key, std::default_delete<Key> > >'
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
.
.
.
simple.cc:33:13: note: in instantiation of function template specialization 'std::vector<std::pair<Key,
std::unique_ptr<Key, std::default_delete<Key> > >, std::allocator<std::pair<Key, std::unique_ptr<Key,
std::default_delete<Key> > > > >::emplace_back<const std::pair<Key, std::unique_ptr<Key,
std::default_delete<Key> > > >' requested here
objects.emplace_back(std::move(record));
^
simple.cc:41:5: note: in instantiation of member function 'CustomContainer<Key>::insert' requested here
q.insert(CustomContainer<Key>::Record(Key(1), std::unique_ptr<Key>(new Key(1))));
I tried the same thing with a custom class instead of a pair and got the same error. I can't seem to get the compiler to call the move constructor instead of the copy constructor no matter how many std::move()s I add. What am I missing?
you're passing a const ref to a unique_ptr and then trying to copy from it (you can only move from a non-const). Pass the entire object and then move from that. Since you're initialising with a temporary (r-value reference), there will be an implicit move at the call site.
patch to fix your code is here:
template <class T> class CustomContainer {
public:
...
bool insert(Record record) { // <-- FIXED
...
}
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.