¿Cuál es la forma correcta de crear un unique_ptr que contiene una matriz que se asigna en la tienda gratuita? Visual Studio 2013 es compatible con esto de forma predeterminada, pero cuando uso la versión 4.8.1 de gcc en Ubuntu, tengo pérdidas de memoria y un comportamiento indefinido.
El problema se puede reproducir con este código:
#include <memory> #include <string.h> using namespace std; int main() { unique_ptr<unsigned char> testData(new unsigned char[16000]()); memset(testData.get(),0x12,0); return 0; }Valgrind dará esta salida:
==3894== 1 errors in context 1 of 1: ==3894== Mismatched free() / delete / delete [] ==3894== at 0x4C2BADC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3894== by 0x400AEF: std::default_delete<unsigned char>::operator()(unsigned char*) const (unique_ptr.h:67) ==3894== by 0x4009D0: std::unique_ptr<unsigned char, std::default_delete<unsigned char> >::~unique_ptr() (unique_ptr.h:184) ==3894== by 0x4007A9: main (test.cpp:19) ==3894== Address 0x5a1a040 is 0 bytes inside a block of size 16,000 alloc'd ==3894== at 0x4C2AFE7: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==3894== by 0x40075F: main (test.cpp:15)Usando la especialización T[] :
std::unique_ptr<unsigned char[]> testData(new unsigned char[16000]()); Tenga en cuenta que, en un mundo ideal, no tendría que usar explícitamente new para crear una instancia de unique_ptr , evitando una posible trampa de seguridad de excepción. Con este fin, C++14 le proporciona la plantilla de función std::make_unique . Vea este excelente GOTW para más detalles. La sintaxis es:
auto testData = std::make_unique<unsigned char[]>(16000);Utilice la versión de matriz:
auto testData = std::unique_ptr<unsigned char[]>{ new unsigned char[16000] };O con c ++ 14, una forma mejor (VS2013 ya lo tiene):
auto testData = std::make_unique<unsigned char[]>( 16000 );Probablemente, una mejor manera sería usar std::vector<unsigned char> en su lugar
#include <vector> #include <string> using namespace std; int main() { vector<unsigned char> testData(0x12, 0); // replaces your memset // bla }La ventaja es que esto es mucho menos propenso a errores y le brinda acceso a todo tipo de funciones, como iteración fácil, inserción, reasignación automática cuando se alcanza la capacidad.
Hay una advertencia: si está moviendo mucho sus datos, un std::vector cuesta un poco más porque también realiza un seguimiento del tamaño y la capacidad, en lugar de solo el comienzo de los datos.
Nota: su memset no hace nada porque lo llama con un argumento de conteo cero.