在push_back到静态向量之后C++取消定位
C++ Deallocation after push_back to static vector
在下面的代码中,我试图实现一个缓存的单例模式(每个乘法(n)只存在一次)。
vector<Multiplication>& Multiplication::cacheVector() {
static vector<Multiplication> cache({Multiplication(0)});
return cache;
}
const Multiplication& Multiplication::getInstance(unsigned int order) {
while (order >= cacheVector().size()) {
cacheVector().push_back(Multiplication(cacheVector().size()));
}
return cacheVector()[order];
}
问题是:当我尝试使用缓存的Multiplication实例时,我会得到一个segfault。Valgrind告诉我,我调用无效读取,因为数据在getInstance函数中是空闲的:
==5471== by 0x4C2054D: std::_Vector_base<tnp::Multiplication, std::allocator<tnp::Multiplication> >::_M_deallocate(tnp::Multiplication*, unsigned long) (stl_vector.h:174)
==5471== by 0x4C2029D: _ZNSt6vectorIN3tnp14MultiplicationESaIS1_EE19_M_emplace_back_auxIJS1_EEEvDpOT_ (stl_vector.h:430)
==5471== by 0x4C1FFDF: _ZNSt6vectorIN3tnp14MultiplicationESaIS1_EE12emplace_backIJS1_EEEvDpOT_ (vector.tcc:101)
==5471== by 0x4C1EE9F: std::vector<tnp::Multiplication, std::allocator<tnp::Multiplication> >::push_back(tnp::Multiplication&&) (stl_vector.h:920)
==5471== by 0x4C1DF52: tnp::Multiplication::getInstance(unsigned int) (multiplication.cpp:83)
乘法没有自己的复制构造函数和那些字段:
class Multiplication {
const unsigned int order;
const vector<Product> valueSum;
const vector<Product> partialDerSum;
const vector<Multiplication>& instances;
(其中instances是对缓存向量的反向引用,order==0除外),释放可能发生在valueSum和partialDerSum向量上。
那么,为什么C++要对我的新乘法实例进行解除分配呢?它不应该直接复制到向量中吗?我希望避免任何显式的堆分配,因为指针间接会在以后的过程中造成一些性能损失。
您还没有指出导致segfault的确切线路,所以我只是胡乱猜测:
可能您在某个地方存储了对Multiplication实例的引用,之后向向量添加了新项,导致向量重新分配其内部内存,因此您的引用指向已释放的内存
不是它崩溃原因的真正答案,而是对这些问题的解释:
那么,为什么C++要对我的新乘法实例进行解除分配呢?难道不应该只是将其复制到矢量中?
事实上,它确实会复制或移动。
让我们稍微描述一下这一行:
cacheVector().push_back(Multiplication(cacheVector().size()));
Multiplication(cacheVector().size())
被分配在某个地方,但cacheVector
的内存不在同一个地方,因此向量在cacheVector
中创建实例时复制或移动(这里肯定是移动)Multiplication
中的数据。
这里有一个小例子可以帮助你理解这一点。
您可以看到,有一个对"normal"构造函数的调用,然后是对move构造函数的调用。然后,编译必须删除移动到向量中的实例,因此它确实会调用使用"普通"构造函数分配的实例上的析构函数。
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 在类定义之后定义一个私有方法
- 在循环C++中指定字符串之后,不会打印该字符串
- C++宏忽略之后的内容
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- strncpy之后的char数组的错误行为
- 计算十进制 c++ 之后的数字
- "x += x--"之后的 x 是什么?
- 类的前向声明之后的类成员函数定义,在类声明之前
- 为什么将双精度转换为 int 似乎在第 16 位数字之后将其四舍五入?
- execlp() 在 fork() 之后无法正常工作
- 我认为我的代码很好,但它在 cin a 之后停止并且没有进一步?
- 如何在MISRA C++之后实施CRTP
- 在 OpenCV 的 namedWindow 之前或之后初始化 Tesseract
- 检测到堆损坏:在正常块 c++ 动态 2D 数组之后
- C++ 如果在 if 为 true 之后运行,为什么还会这样做
- 在 fork() 之后,我在我的程序中不断得到相同的 pid
- OpenSSL C API:如何在程序exec()之后恢复TLS连接?
- 了解在返回值之前和之后使用 EAX 的函数调用
- 在 C++20 之前和之后初始化 std::atomic