【问题标题】:c++ vector of class object pointersc++ 类对象指针向量
【发布时间】:2010-12-20 09:30:26
【问题描述】:

我想要做的基本上是创建两个对象向量,其中一些对象被输入到两个列表中,而一些对象只被输入到一个列表中。我发现的第一个问题是,当我使用 push_back() 将一个对象添加到两个列表中时,该对象被复制了,因此当我从一个列表中更改它时,另一个列表中的对象没有改变。为了解决这个问题,我尝试创建一个指向对象的指针列表作为列表之一。但是,当我稍后访问指针时,数据似乎已损坏,数据成员值都是错误的。以下是我的代码的一些 sn-ps:

向量的定义:

vector<AbsorbMesh> meshList;
vector<AbsorbMesh*> absorbList;

... 向两者添加对象:

AbsorbMesh nurbsMesh = nurbs.CreateMesh(uStride, vStride);

// Add to the absorption list
absorbList.push_back(&nurbsMesh);
// Store the mesh in the scene list
meshList.push_back(nurbsMesh);

访问对象:

if (absorbList.size() > 0)
{
float receivedPower = absorbList[0]->receivedPower;
}

我做错了什么?

【问题讨论】:

  • 为什么meshlist 会存储实际对象的副本?如果你想在两个向量中存储相同的对象,那么两者都应该是指针
  • 您的实际目标是什么(除了 2 个半相似列表)?在 STL 容器中存储指针通常会导致坏事。
  • @Adam 为什么会这样?仅仅是因为指针可能不会被释放?在我看来,将指针(或智能指针)存储在 STL 容器中是件好事,因为这样一来,例如,当容器调整大小时,您就无需为对象的复制构造付费。
  • @Edison:我完全同意智能指针。标准指针往往会导致问题,因为您必须在所有操作中自己处理释放并防止空指针。对于所有可用的库,将标准指针存储在 STL 容器中似乎很愚蠢。如果您担心调整大小的成本,那么您将容量设置得太低了。
  • 在容器中存储指针并没有错。如果你有一个体面的设计,那么应该清楚地了解哪个对象“拥有”内存并负责清理它。对内存分配/释放进行精确控制是使用 C++ 的主要原因之一。如果您不想这样做并在任何地方使用智能指针,请使用 Java 或 C# 之类的东西。

标签: c++ class reference vector pointers


【解决方案1】:

有一些细节缺失,但只是猜测。

nurbsMesh 超出了push_backabsorbList[0]-&gt;receivedPower 之间的范围。

所以现在你的指针向量包含一个指向不再存在的对象的指针。

尝试向您的 AbsorbMesh 类添加一个复制构造函数,然后像这样添加到您的向量中。

absorbList.push_back(new AbsorbMesh(nurbsMesh));
meshList.push_back(nurbsMesh);

不要忘记删除absorbList中的对象,像这样

for(vector<AbsorbMesh*>::iterator it = absorbList.begin(); it != absorbList.end(); it++) {
    delete it;
  }

或者在你的向量中存储一个共享指针而不是一个裸指针。如果您有兴趣,Boost 有一个很好的共享指针实现。请参阅文档here

如果您想对一个向量中的项目进行更新修改另一个向量中的对象,那么您需要在两个向量中存储指针。

使用您的原始要求(更新一个向量中的项目会影响另一个向量中的项目,这是我使用 boost 共享指针的方法。(警告,未经测试的代码)

vector<boost::shared_ptr<AbsorbMesh> > meshList;
vector<boost::shared_ptr<AbsorbMesh> > absorbList;

boost::shared_ptr<AbsorbMesh> nurb = new AbsorbMesh(nurbs.CreateMesh(uStride, vStride));

meshList.push_back(nurb);
absorbList.push_back(nurb);

...
...

if (absorbList.size() > 0)
{
    float receivedPower = absorbList[0].get()->receivedPower;
}

【讨论】:

  • @flyfishr64,该链接无效。我假设您正在链接到某种共享指针?通常是个好主意,但如果 OP 在范围界定方面存在问题,那么通常最好让事情一开始就简单。
  • 不要处理删除对象,而是使用 RAII(资源获取是初始化)并在将对象添加到向量之前将它们包装在智能指针中。 en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
  • 刚刚发现链接失效了……怎么在评论中放一个链接呢?
  • @Glen:问题在于问题中的陈述:“一些对象在一个列表中输入,一些在两个列表中”,如果我们只从一个列表中删除,我们将有内存泄漏。
  • @Naveen,我错过了那一点。我已经更新了我的答案,以展示如何使用 boost::shared_ptr
【解决方案2】:

您正在存储分配在堆栈上的对象的地址。只要您执行push_back() 的方法结束,nurbsMesh 对象就会被销毁。如果您稍后尝试访问此指针,则该对象已被销毁并包含垃圾。您需要的是保留即使在函数超出范围后仍保留的对象。为此,使用new 从堆中为对象分配内存。但是对于每一个新的,你都应该有一个对应的delete。但是在您的情况下,当您将相同的指针推入两个向量时,您将无法删除它。为了解决这个问题,你需要一些类型引用计数机制。

【讨论】:

    【解决方案3】:

    当您尝试从向量中获取指针时,对象被删除。

    试试看

    vector.push_back(new Object);
    

    【讨论】:

      【解决方案4】:

      一旦您解决了其他人提到的问题(存储指向堆栈上对象的指针),您将遇到另一个问题。 vector 可能会重新分配,这会导致其内容移动到另一个位置。

      因此,执行此操作的安全方法是将指针存储在 both 向量中。然后,当然,你需要确保它们被删除......但那是你的 C++。

      【讨论】:

      • 所以如果我按照亚当的建议去做:meshList.push_back(nurbsMesh);吸收列表.push_back(meshList.back());如果重新分配meshList,我会遇到问题吗?什么事件会导致这种情况?插入、删除……其他?
      • 使用该代码,没问题。如果您的向量存储指针,则指针本身会被复制。如果他们自己存储对象,那些对象就会被复制;但是,当然,对其中一个的修改不会出现在另一个中。我认为对vector 的任何修改都可能导致重新分配。实际上,缩小向量不会导致其容量缩小(在 libc++ 中),但我不确定这是否是标准化行为。
      【解决方案5】:

      absorbList.push_back(&amp;nurbsMesh); 错误

      absorbList 保存指向本地对象的指针。当nurbMesh 被销毁时你不能写 absorbList[0]-&gt;

      【讨论】:

        【解决方案6】:

        但是当我稍后访问指针时,数据似乎已损坏

        当您将某物放在向量上时,向量可能会将其从一个物理位置移动到另一个物理位置(尤其是在调整向量大小时),这会使指向该对象的任何指针无效。

        要解决这个问题,您需要在两个向量中存储一个指针(可能是“智能指针”)(而不是让一个向量按值包含对象)。

        如果您要这样做,最好禁用对象的复制构造函数和赋值运算符(通过将它们声明为私有,而不是定义它们)以确保在创建对象后不能搬家了。

        【讨论】:

          【解决方案7】:

          你的例子有几个问题

          AbsorbMesh nurbsMesh = nurbs.CreateMesh(uStride, vStride);
          

          这个对象是在栈上分配的。它是一个纯粹的本地对象。当您到达由 {} 包围的当前块的末尾时,该对象将被销毁。

          absorbList.push_back(&nurbsMesh);
          

          现在你得到了指向最有可能被销毁的对象的指针。

          meshList.push_back(nurbsMesh)
          

          这会在向量上复制一个全新的对象。

          首先将对象压入向量上,然后使用absorbList.push_back( &amp;meshList.back() ) 将指针压入向量上的对象同样是错误的,因为vector::push_back 将重新分配整个向量,使所有指针无效。

          您也许可以先创建所有AbsorbMesh 对象,将它们推送到向量上,然后在向量中获取指向这些对象的指针。只要不碰矢量就没事。

          或者,使用new AbsorbMesh() 在堆上创建对象,但确保在创建的每个指针上调用delete。否则你有内存泄漏。

          第三种解决方案,避免麻烦并使用为您处理对象销毁的smart pointers

          【讨论】:

            【解决方案8】:

            首先,正如其他人指出的那样,您不能在堆栈上分配对象(即,除了new 或类似的东西),并在离开范围后将它们放在周围。

            其次,在 STL 容器中拥有对象并维护指向它们的指针很棘手,因为容器可以移动东西。这通常是个坏主意。

            第三,auto_ptr&lt;&gt; 在 STL 容器中根本不起作用,因为 auto_ptrs 无法复制。

            指向独立分配对象的指针可以工作,但在正确的时间删除它们是很棘手的。

            可能最有效的是shared_ptr&lt;&gt;。将每个向量设为vector&lt;shared_ptr&lt;AbsorbMesh&gt; &gt;,通过new 进行分配,并以轻微的性能成本避免很多麻烦。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2016-04-30
              • 2011-10-01
              • 2011-02-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多