在push_back到静态向量之后的C ++释放

时间:2013-11-27 12:20:28

标签: c++ memory memory-management

在下面的代码中,我尝试实现一个缓存的单例模式(每个乘法(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实例时,我遇到了段错误。 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;

(其中实例是,除了order == 0,对缓存向量的反向引用),重新分配可能发生在valueSum和partialDerSum向量上。

那么为什么C ++会重新分配我的新Multiplication实例呢?它不应该只是复制到矢量? 我想避免任何显式的堆分配,因为指针间接会在未来的某些方面施加一些性能损失。

2 个答案:

答案 0 :(得分:2)

你没有指出导致段错误的确切行,所以只是我的猜测:

可能你在某处存储了对Multiplication实例的引用,然后在向量中添加了新项目,导致向量重新分配了它的内部存储器,因此你的引用指向了解除分配的内存

答案 1 :(得分:1)

对于崩溃的原因并不是真正的答案,而是对这些问题的解释:

  

那么为什么C ++会重新分配我的新Multiplication实例呢?不应该只是   把它复制到载体中?

实际上它会复制或移动。

让我们稍微描述这一行:

cacheVector().push_back(Multiplication(cacheVector().size()));  

Multiplication(cacheVector().size())已分配到某处,但cacheVector的内存不在同一位置,因此向量复制或移动(此处肯定会移动)来自{Multiplication的数据在cacheVector

中创建实例时{1}}

Here is a small example可以帮助您掌握这一点。

您会看到调用“普通”构造函数然后调用移动构造函数。然后编译必须删除移动到向量的实例,因此它会调用使用“普通”构造函数分配的实例上的析构函数。