I'm trying to use the C++0x unique_ptr
class inside a map
like so:
// compile with `g++ main.cpp -std=gnu++0x`
#include <string.h>
#include <map>
#include <memory>
using namespace std;
struct Foo {
char *str;
Foo(char const *str_): str(strdup(str_)) {}
};
int main(void) {
typedef std::map<int, unique_ptr<Foo>> Bar;
Bar bar;
auto a = bar.insert(Bar::value_type(1, new Foo("one")));
return 0;
}
However GCC gives me the following error (shortened, I think this is the relevant part, please test on your own C++ compiler):
main.cpp:19: instantiated from here /usr/include/c++/4.4/bits/unique_ptr.h:214: error: deleted function ‘std::unique_ptr::unique_ptr(const std::unique_ptr&) [with _Tp = Foo, _Tp_Deleter = std::default_delete]’ /usr/include/c++/4.4/bits/stl_pair.h:68: error: used here
I'm really not sure what I've done wrong, this works on MSVC. I have found very similar questions, that seem alike, however their solutions do not work for me.
matt@stanley:/media/data/src/c++0x-test$ gcc --version gcc-4.4.real (Ubuntu 4.4.3-4ubuntu5) 4.4.3
First: Your class Foo is really a very bad approximation of std::string. I predict lots of memory leaks. (Search for "rule of three".)
Second: A pointer is not implicitly convertible to a unique_ptr object (for safety reasons). But the templated pair constructor requires the arguments to be implicitly convertible to the respective value types. GCC seems to allow this but it is a bug. You have to create the unique_ptr object manually. Unfortunately the C++0x draft lacks the following, very useful function template that eases the creation of temporary unique_ptr objects. It's also exception-safe:
template<class T, class...Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
std::unique_ptr<T> ret (new T(std::forward<Args>(args)...));
return ret;
}
In addition, let's use the new emplace function instead of insert :
auto a = bar.emplace(1,make_unique<Foo>("one"));
emplace forwards both arguments to the corresponding pair constructor.
The actual problem you witnessed is that the pair constructor tried to copy a unique_ptr even though such an object is only "movable". It seems that GCC's C++0x support is not yet good enough to handle this situation correctly. From what I can tell, my line from above should work according to the current standard draft (N3126).
Edit: I just tried the following as a workaround using GCC 4.5.1 in experimental C++0x mode:
map<int,unique_ptr<int> > themap;
themap[42].reset(new int(1729));
This is also supposed to work in the upcoming standard but GCC rejects it as well. Looks like you have to wait for GCC to support unique_ptr in maps and multimaps.
I don't believe it's possible to correctly use unique_ptr
in a map::insert
yet. Here's the GCC bug for it:
Bug 44436 - [C++0x] Implement insert(&&)
and emplace*
in associative and unordered containers
It looks like it may be fixed for GCC 4.6 , but it won't build from SVN on vanilla Ubuntu 10.04.1 to confirm.
This is not working as of GCC svn r165422 (4.6.0).
I've just been tinkering with unique_ptr in gcc 4.6.0. Here's some (very ugly) code which works correctly:
std::map<int, std::unique_ptr<int> > table;
table.insert(std::pair<int, std::unique_ptr<int>>(15, std::unique_ptr<int>(new int(42))));
table[2] = std::move(table[15]);
for (auto& i : table)
{
if (i.second.get())
printf("%d\n", *i.second);
else
{
printf("empty\n");
i.second.reset(new int(12));
}
}
printf("%d\n", *table[15]);
The output is 42, empty, 12 - so apparently it works. As far as I can tell, the only 'problem' is that awful looking insert command. 'emplace' isn't implemented in gcc 4.6.0
尝试使用地图的emplace
方法。
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.