smart - C++ unique_ptr y mapa
shared_ptr (4)
Acabo de juguetear con unique_ptr en gcc 4.6.0. Aquí hay un código (muy feo) que funciona correctamente:
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]);
La salida es 42, vacía, 12 - así que aparentemente funciona. Por lo que puedo decir, el único "problema" es ese horrible comando de inserción. ''emplace'' no está implementado en gcc 4.6.0
Estoy tratando de usar la clase C++0x unique_ptr
dentro de un map
así:
// 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;
}
Sin embargo, GCC me da el siguiente error (acortado, creo que esta es la parte relevante, prueba en tu propio compilador de 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
Realmente no estoy seguro de lo que he hecho mal, esto funciona en MSVC. He encontrado preguntas muy similar , que parecen parecidas, sin embargo, sus soluciones no funcionan para mí.
matt@stanley:/media/data/src/c++0x-test$ gcc --version gcc-4.4.real (Ubuntu 4.4.3-4ubuntu5) 4.4.3
No creo que sea posible utilizar correctamente unique_ptr
en un map::insert
aún. Aquí está el error de GCC para ello:
Error 44436 - [C ++ 0x] Implementar insert(&&)
y emplace*
en contenedores asociativos y desordenados
Parece que puede estar arreglado para GCC 4.6 , pero no se construirá desde SVN en Ubuntu 10.04.1 para confirmar.
Actualización0
Esto no funciona a partir de GCC svn r165422 (4.6.0).
Primero: Tu clase Foo es realmente una muy mala aproximación de std :: string. Predigo muchas fugas de memoria. (Buscar "regla de tres".)
Segundo: un puntero no se puede convertir implícitamente a un objeto unique_ptr (por razones de seguridad). Pero el constructor de pares de plantillas requiere que los argumentos sean convertibles implícitamente a los respectivos tipos de valor. GCC parece permitir esto pero es un error. Tienes que crear el objeto unique_ptr manualmente. Desafortunadamente, el borrador de C ++ 0x carece de la siguiente plantilla de función muy útil que facilita la creación de objetos únicos de carácter temporal. También es una excepción segura:
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;
}
Además, usemos la nueva función emplace en lugar de insertar :
auto a = bar.emplace(1,make_unique<Foo>("one"));
emplace reenvía ambos argumentos al constructor del par correspondiente.
El problema real que presenció es que el constructor de pares intentó copiar un unique_ptr aunque ese objeto solo sea "móvil". Parece que el soporte de C ++ 0x de GCC aún no es lo suficientemente bueno para manejar esta situación correctamente. Por lo que puedo decir, mi línea desde arriba debería funcionar de acuerdo con el borrador estándar actual (N3126).
Edición: Acabo de probar lo siguiente como solución alternativa utilizando GCC 4.5.1 en el modo experimental C ++ 0x:
map<int,unique_ptr<int> > themap;
themap[42].reset(new int(1729));
También se supone que esto funciona en el próximo estándar, pero GCC también lo rechaza. Parece que tienes que esperar a que GCC admita unique_ptr en mapas y multimaps.
Trate de usar el método emplace
del mapa.