C ++ unique_ptr и карта - PullRequest
       70

C ++ unique_ptr и карта

24 голосов
/ 11 октября 2010

Я пытаюсь использовать C ++ 0x unique_ptr class внутри map примерно так:

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

Однако GCC выдает мне следующую ошибку (сокращенно, я думаю, что это важная часть, пожалуйста, проверьте на своем собственном компиляторе C ++):

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

Я действительно не уверен, что сделал неправильно, это работает на MSVC. Я нашел очень похожих вопросов, которые кажутся одинаковыми, однако их решения не работают для меня.

matt@stanley:/media/data/src/c++0x-test$ gcc --version
gcc-4.4.real (Ubuntu 4.4.3-4ubuntu5) 4.4.3

Ответы [ 4 ]

27 голосов
/ 11 октября 2010

Во-первых: ваш класс Foo действительно очень плохое приближение std :: string.Я предсказываю много утечек памяти.(Найдите «правило трех».)

Второе: указатель не может быть неявно преобразован в объект unique_ptr (по соображениям безопасности).Но конструктор шаблонных пар требует, чтобы аргументы были неявно конвертируемыми в соответствующие типы значений.GCC, кажется, позволяет это, но это ошибка.Вы должны создать объект unique_ptr вручную.К сожалению, в черновике C ++ 0x отсутствует следующий очень полезный шаблон функции, который облегчает создание временных объектов unique_ptr.Он также безопасен для исключений:

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

Кроме того, давайте использовать новую функцию emplace вместо insert :

auto a = bar.emplace(1,make_unique<Foo>("one"));

emplace перенаправляет оба аргумента в соответствующий конструктор пары.

Фактическая проблема, с которой вы столкнулись, заключается в том, что конструктор пары пытался скопировать unique_ptr, даже если такой объект является только «подвижным».Похоже, что поддержка GCC в C ++ 0x еще недостаточно хороша для правильной обработки этой ситуации.Из того, что я могу сказать, моя строка сверху должна работать в соответствии с текущим стандартным черновиком (N3126).

Редактировать: Я только что попробовал следующее в качестве обходного пути, используя GCC 4.5.1 вэкспериментальный режим C ++ 0x:

map<int,unique_ptr<int> > themap;
themap[42].reset(new int(1729));

Это также должно работать в следующем стандарте, но GCC также отклоняет его.Похоже, вам нужно подождать, пока GCC поддержит unique_ptr в картах и ​​мультикартах.

6 голосов
/ 12 октября 2010

Я не верю, что пока можно правильно использовать unique_ptr в map::insert. Вот ошибка GCC для этого:

Ошибка 44436 - [C ++ 0x] Реализация insert(&&) и emplace* в ассоциативных и неупорядоченных контейнерах

Похоже, что это исправлено для GCC 4.6 , но он не будет собираться из SVN на vanilla Ubuntu 10.04.1 для подтверждения.

Update0

Это не работает с GCC SVN R165422 (4.6.0).

1 голос
/ 01 июня 2011

Я только что возился с unique_ptr в gcc 4.6.0.Вот некоторый (очень уродливый) код, который работает правильно:

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]);

Вывод 42, пустой, 12 - так что, очевидно, он работаетНасколько я могу судить, единственная «проблема» - это ужасно выглядящая команда вставки.emplace не реализован в gcc 4.6.0

0 голосов
/ 30 декабря 2017

Попробуйте использовать emplace метод карты.

...