紧凑向量一个小的内存足迹向量
compact vector a small memory foot print vector
我维护一个旧的C++应用程序,它有很多类,如下所示:
class ClassWithALotOfVectors
{
std::vector<int> _vector1;
std::vector<int> _vector2;
// a lot of other vector datamembers go here
std::vector<double> _vectorN;
};
也就是说,成员为double或int向量的数据类型。问题是,这些矢量永远不会同时填充,因此当我们创建100000个ClassWithALotOfVectors实例时,内存使用量加起来尽管只有10%的矢量在使用,但这一数字还是令人印象深刻。
所以我决定写一个小的"按需分配"向量类。
它是一个围绕std::vector的包装器,其中内部vector仅在第一次访问(使用两个getter-ref()&const_ref()方法)
当我用compact_vector替换ClassWithALotOfVectors类中的std::vector时如下所示:
class ClassWithALotOfVectors2
{
compact_vector<int> _vector1;
compact_vector<int> _vector2;
compact_vector<double> _vectorN;
};
做了一些测试,结果很有希望——内存使用率下降了戏剧性地,但突然发现应用程序不释放内存最后,内存消耗的增长速度要慢得多过去是,但应用程序似乎没有释放内存最后。
你能看看我对compact_vector的实现吗看看你是否能发现内存管理的问题。
template <class T> class compact_vector
{
public:
compact_vector<T>()
:_data(NULL)
{
}
~compact_vector<T>()
{
clear();
}
compact_vector<T>(const compact_vector<T> & rhs)
:_data(NULL)
{
if (NULL != rhs._data)
{
_data = new std::vector<T>(*(rhs._data));
}
else
{
clear();
}
}
// assignment
//
compact_vector<T> & operator=(const compact_vector<T> & rhs)
{
if (this != &rhs)
{
clear();
if (NULL != rhs._data)
{
_data = new std::vector<T>(*rhs._data);
}
}
return *this;
}
compact_vector<T> & operator=(const std::vector<T> & rhs)
{
clear();
if (!rhs.empty())
{
_data = new std::vector<T>(rhs);
}
return *this;
}
const std::vector<T> & const_ref()
{
createInternal();
return *_data;
}
std::vector<T> & ref()
{
createInternal();
return *_data;
}
void clear()
{
if (NULL != _data)
{
_data->clear();
delete _data;
_data = NULL;
}
}
private:
void createInternal()
{
if (NULL == _data)
{
_data = new std::vector<T>();
}
}
private:
compact_vector<T>(const std::vector<T> & rhs)
{
}
compact_vector<T>(std::vector<T> & rhs)
{
}
compact_vector<T>(std::vector<T> rhs)
{
}
std::vector<T> * _data;
};
std::vector
的大多数实现在需要内存之前都不会获取内存,并且向量的大小通常只有几个(3+个可能额外的调试信息)指针。也就是说,std::vector<int>()
不会为任何对象分配空间。我相信你是找错树了。
为什么您的原始代码具有更高的内存使用率?您希望clear()
释放内存吗?
如果是这样,你就错了。clear()
函数破坏所包含的元素,但不释放所分配的内存。考虑添加一个包装器来清除使用以下习惯用法的内存:
std::vector<int>().swap( _data );
前一行所做的是创建一个新的空向量(通常没有附加内存,不是强制的,而是通用的实现),并交换这两个向量的内容。在表达式的末尾,临时包含最初由_data
向量保存的数据,而_data
为空且没有内存(定义了实现)。临时在完整表达式结束时被销毁,内存被释放。
或者,如果编译器支持C++11,则可以在调用clear()
之后使用shrink_to_fit()
。该标准并不要求shrink_to_fit()
实际收缩以适应,但对于空向量,我希望实现能够做到这一点。在调用后调用capacity()
来测试它,看看它是否已降到0。
使用智能指针。在这种情况下,std::unique_ptr
带有手工复制ctor/赋值运算符。突然间,你所有的问题都解决了。这就像魔术!
很抱歉听起来这么刻薄,但内存泄漏总是有相同的答案:智能指针
既然你说它是一个旧的应用程序,不能用它做太多事情。那么在构建过程中保留所有大小为零的向量怎么样
这很乏味,但由于旧的应用程序,预计不会有太多修改。也许这一次值得付出。
class ClassWithALotOfVectors
{
std::vector<int> _vector1;
std::vector<int> _vector2;
// a lot of other vector datamembers go here
std::vector<double> _vectorN;
public:
ClassWithALotOfVectors() : Init() { }
void Init()
{
vector1.reserve(0);
/// Like wise other vectors.
}
};
一次只使用一个向量的想法听起来像union
的概念。毫无疑问,C++有一个名为anonymous union
的元素,它正是这样做的。
class ClassWithALotOfVectors {
public:
union {
std::vector<double> _vector1;
std::vector<double> _vector2;
};
ClassWithALotOfVectors() { new(&_vector1) std::vector<double>; };
~ClassWithALotOfVectors() { _vector1.~vector<double>(); };
};
因为并集不知道该调用哪个元素的构造函数,所以默认构造函数在并集中被禁用,您必须手动构造和解构并集的元素,但我认为这将实现您想要的,将_vector1
和_vector2
别名为同一元素,但将两者都放在ClassWithALotOfVectors
命名空间中,然后在调用CCD_ 17的析构函数时解除分配向量。
有关匿名工会的更多信息,请参阅:CPP参考:匿名工会
- 迭代时从向量和内存中删除对象
- 我在二维向量中是否正确分配了内存
- 字符串共享内存映射的向量
- 具有 STL 向量类型成员的类的复制内存
- 重新分配向量时,向量中的内存会发生什么情况
- 向量的内存位置不连续
- 自己的自定义向量类. 内存重新分配
- 分配具有 2D 向量大小的变量的内存
- 在统一内存 CUDA C/C++ 中分配 2D 向量
- 将 c++ 向量转换为字符 ** 而不会泄漏内存
- 大向量和内存守恒c++
- 如果不初始化结构中的向量,它会自动为空还是具有随机内存位置的值?
- 从函数内对象的向量中释放内存
- C++ 使用数组初始化时的 STL 向量内存管理
- 向量:内存处的范围错误
- 指向对象的指针向量 - 内存泄漏
- 向量内存问题
- c++向量内存不足
- 从复制构造函数外部修改对象成员时导致向量内存损坏,但从复制构造函数内部修改时不会
- 可以使用std::vector capacity/size/rereserve手动管理向量内存分配吗