【问题标题】:preventing data from being freed when vector goes out of scope防止向量超出范围时释放数据
【发布时间】:2009-11-13 05:08:16
【问题描述】:

有没有办法将 std::vector 中包含的数据的所有权(由 T*data 指向)转移到另一个构造中,防止在向量超出范围后“数据”成为悬空指针?

编辑:我不想复制数据(这将是一个简单但无效的解决方案)。

具体来说,我想要类似的东西:

template<typename T>
    T* transfer_ownership(vector<T>&v){
    T*data=&v[0];
    v.clear();
    ...//<--I'd like to make v's capacity 0 without freeing data 
}

int main(){
    T*data=NULL;
    {
        vector<double>v;
        ...//grow v dynamically
        data=transfer_ownership<double>(v);
    }
    ...//do something useful with data (user responsible  for freeing it later)
   // for example mxSetData(mxArray*A,double*data) from matlab's C interface
}

我想到的唯一可以效仿的是:

{
    vector<double>*v=new vector<double>();
    //grow *v...
    data=(*v)[0];
}

然后数据稍后将被释放或(在我的情况下)用作 mxSetData(mxArrayA,doubledata)。然而,这会导致少量内存泄漏(用于处理 v 的容量、大小等的数据结构......当然不是数据本身)。

能不漏吗?

【问题讨论】:

  • 这很令人困惑。另外,请尝试在 C++ 论坛中提问。
  • mxSetData 和 mxArray 是 matlab C 接口的一部分(通过 C mex 文件)。
  • 是的,但这不是一个真正的 Matlab 问题 -- 知道 Matlab 的人来这里帮助你将无法贡献任何东西,除非他们知道 C++。跨度>
  • @spirov,我建议稍微澄清一下你的问题,因为虽然答案正在回答你的问题,但他们似乎不清楚你问的原因。据我所知,您想知道两件不同的事情(1)如何在函数退出后保持向量中的内存(即如何将其从堆栈中存储)和(2)如何传递不复制的向量到外部 API。我认为你的问题中第一个很清楚,但第二个不是。
  • 是的,我想要(1)虽然不一定将它存储在堆栈中(外部 API 接受动态创建的内存),以及(2)(但这部分很简单,我只给出 &v[ 0]).

标签: c++ matlab scope stdvector


【解决方案1】:

一个简单的解决方法是将向量与您拥有的向量交换:

vector<double> myown;

vector<double> someoneelses = foo();

std::swap( myown, someoneelses );

更难但可能更好的方法是为向量编写自己的分配器,并让它从您维护的池中分配。没有亲身经历,不过也不算太复杂。

【讨论】:

  • 简单、“干净”且从性能角度来看非常有效的解决方案。 myown 可以在堆或其他地方创建,以便在其他人超出范围后继续存在。
  • 或更短:foo().swap(myown);
  • 感谢您指出自定义分配器。我将 allocator 继承到具有自定义行为的 allocator_derived 中(如果用户设置了某些标志,请注意不要删除,即在释放向量之前)。这很好用,并且在某些系统上小心谨慎不会泄漏......但不幸的是,并非所有系统都如此。例如,它适用于 mac (gcc 4.2.1) 但在 64 位 Linux (gcc 4.3) 上,声明为 vector > 的向量似乎甚至没有使用派生行为;我不知道为什么。
【解决方案2】:

使用 std::vector 的目的是不必担心其中的数据:

  • 在您的应用程序中始终保留您的矢量;
  • 通过 const-ref 将其传递给其他函数(以避免不必要的复制);
  • 以及需要 &amp;v[0] 指向 T 的指针的提要函数。

如果您真的不想保留您的矢量,您将不得不复制您的数据——您不能转让所有权,因为std::vector 保证它会在超出范围时破坏其内容。在这种情况下,请使用std::copy() 算法。

【讨论】:

  • +1 用于提及 &amp;v[0] 构造以兼容 C 类接口。
  • 第三项是关键,因为将向量的内容传递给外部函数而不复制是 OP 想要的很大一部分。
【解决方案3】:

如果您的向量包含值,您只能复制它们(当您调用 std::copy、std::swap 等时会发生这种情况)。如果您将非原始对象保存在向量中并且不想复制它们(并在另一个数据结构中使用),请考虑存储指针

【讨论】:

    【解决方案4】:

    这样的事情对你有用吗?

    int main()
    {
        double *data = 0;
        {
            vector<double> foo;
            // insert some elements to foo
    
            data = new double[foo.size()];
            std::copy(foo.begin(), foo.end(), &data[0]);
        }
    
        // Pass data to Matlab function.
        delete [] data;
        return 0;
    }
    

    【讨论】:

      【解决方案5】:

      由于您不想在容器之间复制数据,但想在容器之间转移数据的所有权,我建议使用智能指针容器,如下所示。

      void f()
      {
          std::vector<boost::shared_ptr<double> > doubles;
          InitVector(doubles);
      
          std::vector<boost::shared_ptr<double> > newDoubles(doubles);
      }
      

      如果不复制数据,您确实无法在标准容器之间转移数据的所有权,因为标准容器总是复制它们封装的数据。如果您想最小化复制昂贵对象的开销,那么使用引用计数智能指针来包装昂贵的数据结构是一个好主意。 boost::shared_ptr 适合此任务,因为复制它相当便宜。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-11-10
        • 2015-01-09
        • 2018-10-05
        • 1970-01-01
        • 1970-01-01
        • 2021-05-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多