【问题标题】:C++: Vector of Pointers to Objects from another VectorC++:指向来自另一个向量的对象的向量
【发布时间】:2016-05-15 12:00:57
【问题描述】:

我有两个类,类似这样:

class A
{
public:
    B* ptr1;
}

class B
{
public:
    std::vector<A*> list;
}

在主要实现中,我正在做这样的事情:

int main() {

// there are a lot more A objects than B objects, i.e. listOfA.size() >>> listOfB.size()
std::vector<A> listOfA;
std::vector<B> listOfB; 

while (//some loop)
{
    listOfB[jj].list.push_back( &(listofA[ii]) );
    listOfA[ii].ptr1 = &( listOfB[jj] );
}

} // int main end

基本上是这样的。许多A对象被分配给一个B对象,这些A对象作为指针存储在那个指针向量中。此外,每个 A 对象都有一个指向它们所属的 B 对象的指针。对于上下文,我基本上是在使用运行长度编码(用于图像分割)进行连接组件算法,其中 A 类是线段,B 类是图像中的最终对象。

因此,B 类中向量的指针都指向存储在常规向量中的对象。当常规向量超出范围时,应该删除这些对象,对吗?我读过 B 类中的指针向量通常需要编写手动析构函数,但我认为这里不应该是这种情况......

我问的原因当然是因为我的代码不断崩溃。我正在使用华硕 Xtion Pro 相机获取图像,然后对每张图像执行算法。奇怪的是,每当我用力摇晃相机时,程序就会崩溃。当相机静止或仅移动一点点或缓慢移动时,什么也不会发生。此外,当我使用不同的算法(也是连接的组件,但没有运行长度编码并且也不使用指针)时,无论我如何摇晃相机,都不会崩溃。此外,在 Debug 模式下(运行速度比 Release 模式慢得多),也没有任何崩溃。

我尝试为 B 类中的指针向量创建析构函数,但它导致“块有效”错误,所以我猜它删除了两次。 我还尝试用 c++11 std::shared_ptr 替换每个指针,但这只会产生非常不规则的行为,并且当我摇晃相机时代码仍然崩溃。

我基本上只是想知道在内存泄漏和指针处理方面,上面显示的代码是否正常,或者代码中是否存在可能导致崩溃的错误。

编辑(已解决): 解决方案(请参阅已接受的答案)是确保向量 'listOfB' 在运行时不会调整大小,例如使用 'reserve() ' 为它预留足够的空间。完成此操作后,一切正常!显然它起作用了,因为如果向量'listOfB'被调整大小(通过push_back()),其中B实例的内部内存地址也会改变,导致A实例中的指针(指向B实例)到现在指向错误的地址 - 从而导致麻烦,从而导致崩溃。

关于相机抖动,显然,抖动相机会导致图片非常模糊,需要分割的元素很多,从而增加了对象的数量(即导致 listOfB 需要更大的尺寸)。于是,谜团解开了!非常感谢! :-)

【问题讨论】:

  • 我觉得这个设计坏了。 listofB 将增长并重新分配其内部数据数组,使存储在 A 实例的 ptrs 中的所有地址无效。通常的算法会将数据大小增加 2 倍,这可以解释如果没有太多数据到达,你会在一段时间内很好。此外,只要旧数据的内存仍在程序的地址空间中(特别是如果它在同一内存页面上,例如因为新数据也适合它),程序可能不会崩溃访问它只是检索旧数据。
  • @PeterA.Schneider 这很有道理!所以B实例中的指针向量不是问题,而只是A实例中的指针,我猜(由于listOfB的大小调整,这会改变内存地址)?如果您对此做出回答,我会接受。

标签: c++ pointers c++11 vector connected-components


【解决方案1】:

我认为设计已损坏。 listofB 将增长(您执行 push_backs)并重新分配其内部数据数组,使存储在 A 实例的 ptrs 中的所有地址无效。通常的算法会将数据大小增加 2 倍,这可以解释如果没有太多数据到达,你会在一段时间内很好。此外,只要旧数据的内存仍在程序的地址空间中(特别是如果它在同一内存页面上,例如因为新数据也适合它),程序可能不会崩溃访问它只是检索旧数据。

在更具建设性的说明中:如果您提前知道最大元素,您的解决方案将起作用,这可能很难(假设您明年将获得 4k 相机 ;-))。在这种情况下,顺便说一句,你可以使用一个简单的静态数组。

也许您也可以使用std::map 来存储A 对象,而不是简单的向量listofA。每个 A 对象都需要某种唯一 ID(最简单的情况下是 A 中的静态计数器)才能用作映射的键​​。 Bs 将存储密钥,而不是 As 的地址。

【讨论】:

  • 目前,我知道可以出现的最大元素数量有一个很好的限制,所以我想我现在会尝试使用一个简单的数组。不知道数组填充部分的确切大小很烦人,但我想我可以使用一个外部计数器。但是正如您所说,这基本上只是一个临时解决方案,因为限制会因相机甚至捕获的地形而异。也许我会尝试根据这些标准制定一个简单的限制公式。当我有时间时,我也会研究 std::map 。再次感谢! :-)
【解决方案2】:

假设您在构建网络的方式上没有犯错,您应该没问题。您将不得不发布更多代码来评估它。此外,在更改其中一个 vector 后,您也不能使用其中任何一个,因为如果它们重新分配其成员,则指向它们的所有指针都将失效。但是使用原始指针指向托管对象是构建网络的正确方法。

托管对象我的意思是对象的生命周期保证比网络更长,并且其内存将被自动释放。所以它们应该是容器的元素或由某种智能指针管理的对象。

但是听起来您遇到了硬件问题。

【讨论】:

  • 我现在尝试了几件事,你们之前说的没错:我增加了 listOfB 保留的空间(因此,确保 listOfB 不会调整大小),现在一切正常!我还对其进行了一些测试,可以确认每次代码生成的 listOfB 大小大于保留的大小时,它都会崩溃!我猜想调整大小会导致这些对象中的指针向量做一些奇怪的事情。无论如何,如果您可以再次发布该答案,我会接受。无论如何,非常感谢这里的每一个人! :-)
猜你喜欢
  • 1970-01-01
  • 2011-10-01
  • 2011-02-11
  • 1970-01-01
  • 2018-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-19
相关资源
最近更新 更多