C++成员变量的值是否输出会影响其值的改变

3

我有一个名为ZoneDeVie的类,其中包含一个指向Bacterie*向量的向量。Bacterie类包含一个int类型的值energie(默认设置为10)和一个名为toString()的函数,该函数用于打印该值。在ZoneDeVie的构造函数中,我构建了一个2D表格,并使用Bacterie的默认实例填充每个单元格。然后,在我的主方法中,我测试通过打印表格中最后一个BacterietoString()来检查。由于某种原因,它返回一个随机的、非常大的int值(通常是3753512之类的值)。但是,如果我在ZoneDeVie的构造函数中调用Bacterie的toString()方法,则主方法将正确地打印出结果。

#include <iostream>
#include <sstream>
#include <vector>
using namespace std;

class Bacterie {
public:
    Bacterie() { this->energie = 10; }
    string toString() {
        stringstream ss;
        ss << "Energie: " << this->energie;
        return ss.str();
    }
protected:
    int energie;
};

class ZoneDeVie {
public:
    ZoneDeVie(int width, int height) {
        Bacterie* bac = new Bacterie();

        // without this [following] line, the call to `toString`
        // in the main method will return an obnoxiously-large value
        //bac->toString();
        for (int i=0; i<height; i++) {
            vector<Bacterie*> bacvec = vector<Bacterie*>();
            this->tableau.push_back(bacvec);
            for (int j=0; j<width; j++) {
                this->tableau[i].push_back(bac);
            }
        }
    }
    vector<vector<Bacterie*> > tableau;
};

int main(int argc, char *argv[]) {
    int x,y;
    x = 9; y = 39;
    ZoneDeVie zdv = ZoneDeVie(10,40);
    cout << "zdv(" << x << "," << y << ") = " << zdv.tableau[x][y]->toString();

    return 0;
}

输出结果(在ZoneDeVie的构造函数中调用“toString()”):zdv(9,39) = 能量:10

输出结果(在ZoneDeVie的构造函数中未调用“toString()”):zdv(9,39) = 能量:4990504

为什么我需要在主方法中调用toString()方法之前先调用它,才能使它按预期工作?


你是否定义了析构函数 ZoneDeVie::~ZoneDeVie - mfontanini
你可能会因为写入或读取超出数组边界、访问不应该访问的某些内存部分、或者在某个地方使用未初始化的基本类型或指针而产生一些未定义行为。 - juanchopanza
所有指针的原因是什么? - chris
1
好的,我们猜不出来。请发一个SSCCE:http://sscce.org/ - mfontanini
@weberc2 好的,我修改了我的答案。这应该解决问题了。 - mfontanini
显示剩余5条评论
2个回答

1
你的for循环中的结束条件被交换了。你应该先迭代width,然后再迭代height
class ZoneDeVie {
public:
    ZoneDeVie(int width, int height) {
        Bacterie* bac = new Bacterie();

        for (int i=0; i<width; i++) {
            vector<Bacterie*> bacvec = vector<Bacterie*>();
            this->tableau.push_back(bacvec);
            for (int j=0; j<height; j++) {
                this->tableau[i].push_back(bac);
            }
        }
    }
    vector<vector<Bacterie*> > tableau;
};

这将编译并提供正确的输出。


虽然正式语义要求在这里进行复制构建,但标准明确允许省略它,我不知道有哪个编译器不会省略它。 - James Kanze
我定义了ZoneDeVie::~ZoneDeVie,但它什么也没做({})... 无论如何,您能否更明确地解释为什么在ZoneDeVie构造函数中调用toString()与主方法中发生的事情有任何关系? - weberc2
另外,删除ZoneDeVie ::〜ZoneDeVie也不会对结果产生任何影响。 - weberc2
另外,值得一提的是,我想支持你的回答;但是,有人给我的问题投了反对票,使我无法达到最低声望值以进行点赞。很抱歉:( - weberc2
好的,很公平。谢谢你的帮助。 :) - weberc2
显示剩余2条评论

1

这段代码存在几个问题。

  1. 不清楚 Bacterie 的默认构造函数是做什么的。

  2. 不清楚 ZoneDeVie::tableau 是什么以及如何使用本地向量 bacvec

  3. 不清楚如何定义类 ZoneDeVie 的复制构造函数和 operator=(两者都在 main() 中使用)。

  4. 似乎表中的所有条目都用指向相同的 Bacterie bac 的指针初始化了。


  1. Bacterie::Bacterie() {this->energie = 10;}
  2. ZoneDeVie::tableau 是之前提到的二维向量。 bacvec 是表格中的一行,用于填充在 ZoneDeVie 构造函数中创建的表格。
  3. operator= 没有被重载,ZoneDeVie 不是一个派生类。
  4. 那是正确的。
- weberc2
@weberc2:那应该是问题的一部分,而不是评论。 - David Rodríguez - dribeas
@DavidRodríguez-dribeas,这些信息已经根据问题的内容可得出或推导出来。重复表述似乎有点儿愚蠢。如果我的回答不够清晰明了,我已经编辑了回答并增加了一个可编译的示例。 - weberc2
@weberc2:我不确定你是否意识到,如果显而易见的事情是真的,那就不会有问题了。在寻求帮助时,请确保帮助他人帮助你。基于假设猜测代码可能出错的情况是没有意义的。 - David Rodríguez - dribeas
我没有做出任何假设。我提供了我代码的所有相关部分,并解决了他所关注的每一个问题;然而,我认为在我的回答中强调那些在代码中显而易见的事情并没有太大的价值。如果提问者误读了可用的材料,那么无论前面提到的材料有多准确或完整,仍然可能存在问题。考虑到这种情况,我觉得最好在这里解决他的问题,而不是延长我的回答。 - weberc2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接