【问题标题】:Vector Iterators Casting向量迭代器铸造
【发布时间】:2009-09-03 09:03:07
【问题描述】:

嘿,在 C++ 中,我有一个向量类型:

vector<BaseClass*> myVector;

我在其中插入(push_back)派生类的指针。

现在,我想弹回它的元素,所以我这样做:

vector<ADlgcDev*>::iterator iter;

for (iter = myVector.rbegin(); iter != myVector.rend(); iter++)
{
 // but before I pop it, I need to shutdown it down
 // so I cast this
 // but this way, I'm unable to call the function
 (DerivedClass*(*iter))->Shutdown();

 myVector.pop_back();
}

但正如我在弹出之前在 cmets 中提到的那样,我需要调用它的 Shutdown() 方法并且演员表也无法正常工作。有什么决议吗?还是不可能?

【问题讨论】:

  • 顺便说一句,你的循环坏了——要么保持 for 循环不变并删除 myVector.pop_back(),要么将其保留并更改为检查 back() 元素的 while 循环sbi 建议的时间。
  • 如果您在脑海中通过包含 10 个项目的数组来完成这些步骤,您会发现您只处理了第一个 5,因为到那时您已经使用 pop_back() 删除了最后 5 个。
  • 更糟糕的是:使用了 rbegin() 和 end(),因此行为将是未定义的
  • 关于 rbegin() 和 end():这不会编译,因为 rbegin() 是一个 reverse_iterator
  • 这只是一个错字,已更正!

标签: c++ vector pointers casting


【解决方案1】:
while (!myVector.empty())
{
  ((DerivedClass*)(myVector.back()))->Shutdown();
  myVector.pop_back();
}

注意事项:

  • 您可能应该使用dynamic_cast 而不是硬演员。 (如果确定向量中只有DerivedClass对象,为什么不是std::vector&lt;DerivedClass&gt;?)
  • 您可能根本不需要强制转换,因为Shutdown() 应该在基类中声明。
  • 您也应该删除这些对象,然后再将它们从矢量中弹出。 (但可能并非如此。)
  • 您可能应该使用调用Shutdown()(可能还有delete)的智能指针。

编辑:使用std::vector&lt;T&gt;::clear()as shown by markh44 可能比pop_back() 更好。

【讨论】:

  • 很好的建议,尤其是第 2 条。但是 stefaanv 是对的,构造函数风格的转换不适用于指针类型——按照他的建议去做。
  • 我同意 cmets,我喜欢新循环
  • 更好——完全摆脱Shutdown() 并将功能放入析构函数中(必须变为virtual,因为您将通过基类指针删除派生类)。请改用vector&lt;boost::smart_ptr&lt;BaseClass&gt; &gt;,这样您就不需要记住做任何事情了!
  • 谢谢,我在演员表中添加了另一对括号。它现在看起来真的很丑(很好,反正很臭),但仍然很难 grep (坏)。我应该改用选中的dynamic_cast,但是我不得不重新写下我的笔记……不过我觉得很脏。 :-)
  • 这只是一个例子,如果你去掉'_',它甚至可以编译;)
【解决方案2】:

你能在 BaseClass 中将 Shutdown 设为一个虚函数吗?那么你就不需要演员表了。

此外,您在迭代时可能无法从向量中删除项目。我会这样做:

vector<BaseClass*>::iterator iter;

for (iter = myVector.rbegin(); iter != myVector.rend(); iter++)
{
    (*iter)->Shutdown();
}
myVector.clear();

编辑:另外,++iter 通常比 iter++ 更受欢迎。

【讨论】:

  • 我猜 rbegin()end() 也可能会带来麻烦。不过,使用clear() 是个好主意。
  • @markh44:这就是问题所在。这是原始代码的问题之一。
  • @sbi 没关系,然后我以为我终于疯了。
【解决方案3】:

构造函数转换不适用于指针。如果您确定,请使用 static_cast 或使用 dynamic_cast 并检查。

【讨论】:

    【解决方案4】:

    如果 Shutdown() 是 Base 类的虚方法,即 BaseClass::ShutDown() 你应该直接调用 iter->ShutDown();

    否则,如果方法不是虚拟方法,则应使用dynamic_cast

    vector<ADlgcDev*>::iterator iter;
    
    for (iter = myVector.rbegin(); iter != myVector.end(); iter++)
    {
     DerivedClassA* a = dynamic_cast<DerivedClassA*>( *iter ) ;
     if ( a ) a->ShutDownA();
     else
     {
     DerivedClassB* b = dynamic_cast<DerivedClassB*>(*iter);
     if ( b ) b->ShutDownB();
     // ... repeat for every class in hierarchy that might be in the vector.
     }
     myVector.pop_back();
    }
    

    无论如何,您可能正在泄漏内存,除非 ShutDown() 从自身中删除对象(这通常是一个坏主意),或者您保留重复的指针并在其他地方删除它们,这是另一个冒险的想法。

    【讨论】:

    • 您是否查看过 iter 的初始化对象以及与之比较的对象?您会选择哪一个以使myVector.pop_back() 不会对迭代器造成严重破坏?如果有几个派生类具有ShutDownX()函数,它应该非常很可能是在基类中声明的虚函数。
    • 我只是对他的设计进行了最小的改动。当然要推导,整个循环可以写成两行。
    猜你喜欢
    • 2011-03-16
    • 2021-10-08
    • 1970-01-01
    • 1970-01-01
    • 2011-11-15
    • 2017-08-29
    • 1970-01-01
    • 2018-07-09
    相关资源
    最近更新 更多