代码行以后不能使用两行

时间:2012-12-29 22:42:28

标签: c++ list function

这令人费解。我需要在我的程序中使用函数CCountry :: getName()。奇怪的是,在测试它是否可以工作时,它可以在一个地方工作,但不会工作两行,我无法弄清楚原因。例如......

while(line != "---" && line != "------")
    {
        CCountry *tempCountry = new CCountry(line);
        cout << tempCountry->getName() << flush;
        (*tempContinent).addCountry(*tempCountry);
        getline(filestr, line);

    }

作品。它按顺序列出了所有国家/地区名称。然而...

    while(line != "---" && line != "------")
    {
        CCountry *tempCountry = new CCountry(line);
        (*tempContinent).addCountry(*tempCountry);
        getline(filestr, line);
        cout << tempCountry->getName() << flush;
    }

不起作用。它甚至无法打印一个国家名称,而是在调用getName()的行中抛出一个seg错误。

这里有两个函数,getName()和addCountry()

供进一步参考
string CCountry::getName()
{
return *name;
}

void CContinent::addCountry(CCountry country)
{
(*countries).push_back(country);
}

根据请求,这是CCountry构造函数:

CCountry::CCountry(string in_name)
{
name = new string;
*name = in_name;
player = new int;
*player = -1;
units = new int;
*units = 0;
neighbors = new list<CCountry>;
}

5 个答案:

答案 0 :(得分:3)

我可能会对这段代码中的一长串错误发出嘎嘎声,但导致你错误的那一行最终是因为以下原因:

您的CCountry课程没有练习Rule of 3必须,因为它有动态分配的成员。(顺便说一下,甚至不需要)

您正在通过按值获取国家/地区的成员函数将您的CCounty对象添加到您的大陆。此时制作对象的浅表副本。然后将其推入非洲大陆的容器中,这会产生另一个浅色副本。在addCountry()退出时,原始浅拷贝被销毁,并且在返回到您的调用代码的过程中,CCountry对象的内部已被破坏。因此,你的本地(不应该首先动态分配,顺便说一句,顺便说一句)是正式的。

猜猜是什么......你的大陆集装箱里面的那个。

我可能会首先考虑CCountry对象本身。我个人会在CContinent类而不是CCountry中管理一个CCountry的邻居,因为无论如何管理CCountry对象的集合,而是管理它们自己的对象。如果您决定坚持使用当前模型,CCountry的潜在替代方案可能是这样的:

class CCountry
{
public:
    CCountry(const std::string& name)
       : name(name), player(0), units(0)
    {
    }

    // properties
    const std::string& getName() const { return name; };
    int getPlayer() const { return player; };
    void setPlayer(int player) { this->player = player; };
    int getUnits() const { return units; };
    void setUnits(int units) { this->units = units; };

    // neighbor access
    const std::list<const CCountry*> getNeighbors() const
    {
        std::list<const CCountry*> res;
        for (auto it=neighbors.begin(); it != neighbors.end(); ++it)
            res.push_back(it->second);
        return res;
    }

    // adding a new neighbor
    void addNeighbor(const CCountry& other)
    {
        neighbors[ other.getName() ] = &other;
    }

private:
    std::string name;
    int player;
    int units;
    std::map<std::string, const CCountry*> neighbors;
};

但是请注意:追求这样的模型(正如你所看到的,你的原始模型),将会有潜在的陷阱,特别是CCountry可能指向另一个CCountry的技术上它没有'拥有。这就是为什么我更喜欢邻居关联由CContinent类本身管理,因为它将拥有CCountry和他们的邻居协会。

答案 1 :(得分:2)

我怀疑你已经定义了这样的CCountry析构函数:

~CCountry() {
    delete name;
    delete player;
    delete units;
    delete neighbors;
}

但我怀疑你有CCountry定义了一个副本构造函数。这意味着编译器正在生成这样的复制构造函数:

CCountry(CCountry const &that) :
    name(that.name),
    player(that.player),
    units(that.units),
    neighbors(that.neightbors)
{ }

现在,CContinent::addCountry定义为CCountry,而不是CCountry &。因此,当您执行(*tempContinent).addCountry(*tempCountry)时,您的程序将使用该编译器定义的*tempCountry复制构造函数生成CCountry的(临时)副本。

所以现在你的程序有两个独立的CCountry实例:一个由tempCountry指向,另一个在CContinent::addCountry的{​​{1}}参数中。但由于编译器定义的复制构造函数的工作方式,两个实例都有country个成员变量指向同一个name实例。

删除临时副本后,其析构函数将删除该字符串实例。现在string指向的实例在其tempCountry成员变量中有一个悬空指针。当您尝试取消引用name中的悬空指针时,行为未定义,并导致您的分段错误。

将您的getNamenameplayerunits成员变量更改为而非成为指针。它们应该只是普通类型,如下:

neighbors

您可能还希望将功能更改为引用而不是副本。

答案 2 :(得分:0)

是否有可能在CCountry的构造函数中导致某种覆盖?听起来对我来说。

答案 3 :(得分:0)

在CCountry的构造函数中,您使用new string分配名称,在析构函数中,您可以使用delete name释放它。我不知道为什么你需要这样做,将string而不是string*存储为name的成员CCountry可能更简单。当您将CCountry作为参数传递给CContinent::addCountry时,将创建临时副本,然后将其删除,这将导致删除在CCountry::name的多个实例之间共享的CCountry。为避免这种情况,您需要使用string代替string*作为name的成员CCountry,或者实施您自己的CCountry复制构造函数。

答案 4 :(得分:0)

此代码存在许多问题,但对于初学者来说, CCountry是否具有值语义或是实体类型。 在第一种情况下,你不应该指向它,或者 使用new动态分配它。你应该确保这一点 它可以被正确地复制和分配。在第二个,你 不应该通过值传递给CContinent::addCountry(和你 应该通过制作副本来禁止复制和分配 构造函数和赋值运算符私有,或通过派生 来自boost::noncopyable)。

您没有显示CCountry的定义,而是您的方式 初始化name表示您正在假设 std::string是一个实体对象。它不是 - 它有价值 语义,几乎没有你会有的情况 指向std;:string的指针。 (唯一的例外是a 函数参数或返回值,您想要支持的位置 一个空指针,用于指示值的缺失。)相同 适用于playerunitsneighbors:上下文 你将有一个指向int或标准的指针 容器仅限于需要空指针的情况 表明没有价值。

您也不显示使用复制构造函数,赋值 运算符或析构函数。如果您要删除内存中的内存 析构函数,并没有复制构造函数,这是 问题的根源。编译器生成了复制构造函数 做一个浅拷贝,这意味着当你打电话 CContinent::addCountry,你最终得到两个对象 相同的指针。当参数被破坏时,如果它被删除 任何事情,这会使作为参数传递的对象无效(其中 包含相同的指针)。有不同的处理方式 这,但几乎在所有情况下,最合适的是不 使用指针。 (例如,班级std::string有副本 执行深层复制的构造函数,因此使用它没有问题。)

最后,在一个完全不相关的问题上:在你的课程前加上 C的名称​​不是个好主意。微软采用了这一点 他们的班级名称的约定(至少在他们的一些 库),任何看到像CCountry这样名字的读者都会 假设它是来自其中一个Microsoft库的类, 并将尝试在Microsoft文档中找到它,而不是 在你的代码中。