使用 unique_ptr 和适当的容器进行内存管理
Use unique_ptr and appropriate container to do memory management
首先,我的动机是在类似 C 的计算内核之上进行高效的内存管理。我尝试使用 std::unique_ptr
和 std::vector
,我的代码如下所示
// my data container
typedef std::unique_ptr<double> my_type;
std::vector<my_type> my_storage;
// when I need some memory for computation kernel
my_storage.push_back(my_type());
my_storage.back.reset(new double[some_length]);
// get pointer to do computational stuff
double *p_data=my_storage.back.get();
注意这里在实践中p_data
可能存储在一些其他容器(例如map)中以根据域问题索引每个分配的数组,尽管如此,我的主要问题是
这里std::vector
是个不错的选择吗? std::list
/set
?
等其他容器呢?
是不是我的分配方式存在根本问题?
假设我使用p_data
进行一些操作后,现在我想释放原始指针指向的内存块p_data
,这里的最佳实践是什么?
首先,如果你正在分配一个数组,你需要使用特化std::unique_ptr<T[]>
,否则你不会在内存释放时得到delete []
,而是一个简单的delete
。
std::vector
是一个不错的选择,除非您有任何明确的理由使用不同的东西。例如,如果您要在容器内移动许多元素,那么 std::list
可以执行得更好(更少的 memmove
操作来移动东西)。
关于如何管理内存,主要取决于使用模式。如果 my_storage
主要负责所有事情(在您的规范中是这样,因为 unique_ptr
表示所有权),这意味着它将是唯一可以释放内存的人。这可以简单地通过调用 my_storage[i].reset()
.
来完成
请注意,如果释放内存,将托管对象的原始指针存储在其他集合中会导致悬空指针,例如:
using my_type = std::unique_ptr<double[]>;
using my_storage = std::vector<my_type>;
my_storage data;
data.push_back(my_type(new double[100]));
std::vector<double*> rawData;
rawData.push_back(data[0].get());
data.clear(); // delete [] is called on array and memory is released
*rawData[0] = 1.2; // accessing a dangling pointer -> bad
这可能是个问题,如果 data
是最后发布的,那么就没有问题,否则你可以存储对 std::unique_ptr
的 const 引用,这样至少你可以检查内存是否仍然有效,例如:
using my_type = std::unique_ptr<double[]>;
using my_managed_type = std::reference_wrapper<const my_type>;
std::vector<my_managed_type> rawData;
将 std::unique_ptr
与任何 STL 容器一起使用,包括 std::vector
,通常都没有问题。但是您没有以正确的方式使用 std::unique_ptr
(您没有使用它的数组专用版本),并且您根本不需要求助于使用 back.reset()
。试试这个:
// my data container
typedef std::unique_ptr<double[]> my_type;
// or: using my_type = std::unique_ptr<double[]>;
std::vector<my_type> my_storage;
my_type ptr(new double[some_length]);
my_storage.push_back(std::move(ptr));
// or: my_storage.push_back(my_type(new double[some_length]));
// or: my_storage.emplace_back(new double[some_length]);
首先,我的动机是在类似 C 的计算内核之上进行高效的内存管理。我尝试使用 std::unique_ptr
和 std::vector
,我的代码如下所示
// my data container
typedef std::unique_ptr<double> my_type;
std::vector<my_type> my_storage;
// when I need some memory for computation kernel
my_storage.push_back(my_type());
my_storage.back.reset(new double[some_length]);
// get pointer to do computational stuff
double *p_data=my_storage.back.get();
注意这里在实践中p_data
可能存储在一些其他容器(例如map)中以根据域问题索引每个分配的数组,尽管如此,我的主要问题是
这里
std::vector
是个不错的选择吗?std::list
/set
? 等其他容器呢?
是不是我的分配方式存在根本问题?
假设我使用
p_data
进行一些操作后,现在我想释放原始指针指向的内存块p_data
,这里的最佳实践是什么?
首先,如果你正在分配一个数组,你需要使用特化std::unique_ptr<T[]>
,否则你不会在内存释放时得到delete []
,而是一个简单的delete
。
std::vector
是一个不错的选择,除非您有任何明确的理由使用不同的东西。例如,如果您要在容器内移动许多元素,那么 std::list
可以执行得更好(更少的 memmove
操作来移动东西)。
关于如何管理内存,主要取决于使用模式。如果 my_storage
主要负责所有事情(在您的规范中是这样,因为 unique_ptr
表示所有权),这意味着它将是唯一可以释放内存的人。这可以简单地通过调用 my_storage[i].reset()
.
请注意,如果释放内存,将托管对象的原始指针存储在其他集合中会导致悬空指针,例如:
using my_type = std::unique_ptr<double[]>;
using my_storage = std::vector<my_type>;
my_storage data;
data.push_back(my_type(new double[100]));
std::vector<double*> rawData;
rawData.push_back(data[0].get());
data.clear(); // delete [] is called on array and memory is released
*rawData[0] = 1.2; // accessing a dangling pointer -> bad
这可能是个问题,如果 data
是最后发布的,那么就没有问题,否则你可以存储对 std::unique_ptr
的 const 引用,这样至少你可以检查内存是否仍然有效,例如:
using my_type = std::unique_ptr<double[]>;
using my_managed_type = std::reference_wrapper<const my_type>;
std::vector<my_managed_type> rawData;
将 std::unique_ptr
与任何 STL 容器一起使用,包括 std::vector
,通常都没有问题。但是您没有以正确的方式使用 std::unique_ptr
(您没有使用它的数组专用版本),并且您根本不需要求助于使用 back.reset()
。试试这个:
// my data container
typedef std::unique_ptr<double[]> my_type;
// or: using my_type = std::unique_ptr<double[]>;
std::vector<my_type> my_storage;
my_type ptr(new double[some_length]);
my_storage.push_back(std::move(ptr));
// or: my_storage.push_back(my_type(new double[some_length]));
// or: my_storage.emplace_back(new double[some_length]);