【问题标题】:C++: calling member functions within constructor?C++:在构造函数中调用成员函数?
【发布时间】:2010-05-10 23:21:59
【问题描述】:

以下代码引发运行时错误:

#include <iostream>
#include <iterator>
#include <ext/slist>

class IntList :  public __gnu_cxx::slist<int> {
public:
    IntList() { tail_ = begin(); } // seems that there is a problem here
    void append(const int node) { tail_ = insert_after(tail_, node); }

private:
    iterator tail_;
};

int main() {
    IntList list;

    list.append(1);
    list.append(2);
    list.append(3);

    for (IntList::iterator i = list.begin(); i != list.end(); ++i) {
        std::cout << *i << " ";
    }

    return 0;
}

看来问题出在构造函数IntList()。是不是因为调用了成员函数begin()

【问题讨论】:

  • 你为什么要自己定义iterator?而且,如果这个 slist 是基于 STL slist 的,那么它没有虚拟析构函数,所以你可能不应该公开(或根本不)从它派生。
  • 对不起。 typedef 是一个错误。我已经修改过了。
  • 对我来说问题是 append()。您是否使用 -g 标志编译过。此外,添加打印语句以查看崩溃的位置可能会有所帮助
  • @James 和 poerboy。技术上是的。但与问题无关。
  • @Martin:在这种情况下很不寻常,因为slist&lt;T&gt;::iterator 是一个公共类型定义,所以完全没有必要。如果公共基类具有公共 typedef,则没有理由在派生类中重新声明它。至于我的评论与问题无关,这就是为什么我将其发布为评论而不是答案。使用 cmets 提出问题或建议(例如,不要从没有虚拟析构函数的类派生)是常见的做法。

标签: c++


【解决方案1】:

看起来你是在 end() 之后插入的;

在构造函数的主体中

IntList() { tail_ = begin(); }

基类已经构建,可以调用它的成员,但是对于一个空列表,它应该返回end();

【讨论】:

  • 这看起来不错;传递给insert_after() 的迭代器必须是可取消引用的,而end() 则不能。
  • 所以,我想添加私有成员tail_ 来跟踪列表的尾部,以便我可以更快地追加元素。我该怎么做?
  • 你不应该从 slist 派生,首先。但要解决这个特定问题,请尝试调用insert()
  • 谢谢 WilhelmTell!也许我应该使用 slist 作为我的列表的底层容器,就像 如何基于
  • @powerboy 是的,这更有意义。要么将slist 对象作为数据成员带入IntList,要么从slist 私下派生。只有当客户端尝试创建IntList 的多态对象时才会出现问题,例如:slist* l = new IntList(); 和稍后的delete l;。发生这种情况时,IntListslist 部分将正确清理,但 IntList 不会:它将导致未定义的行为。如果您不公开从 slist 派生,那么用户根本无法创建具体的 IntList 类型的多态对象,因此它是安全的。
【解决方案2】:

slist 的文档表明提供给 insert_after 的迭代器必须是可取消引用的。

由于您的列表为空,因此 begin() 返回 end() 并且因此不可取消引用。

在此处查看文档:

http://www.sgi.com/tech/stl/Slist.html

iterator insert_after(iterator pos, const value_type& x)

pos 必须是 *this 中的可解引用迭代器。 (也就是说,pos 可能不是 end()。)在 pos 之后插入 x 的副本。返回值是一个指向新元素的迭代器。复杂性:恒定时间。

【讨论】:

    【解决方案3】:

    您的问题不在于构造函数,而在于第一次调用append()。因为您的列表为空begin() 等于end()end() 是一个有效的迭代器,但之后的不是。要解决该特定问题,请尝试致电 insert()

    也就是说,快速查看&lt;ext/slist&gt; 可以确认slist 的析构函数不是虚拟的,这意味着slist 并非旨在派生自。

    【讨论】:

      【解决方案4】:

      .begin() 如果您的集合中没有元素,则无效。

      【讨论】:

      • begin() 在容器上始终有效。如果容器中没有元素,那么begin() == end()(当然,假设这个 GNU 扩展 slist 是 STL slist 的实现)。
      • 我想每天都能学到一些新东西。 :-)
      猜你喜欢
      • 2011-12-07
      • 2012-01-10
      • 2011-03-06
      • 1970-01-01
      • 2012-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多