【发布时间】:2012-06-25 12:42:54
【问题描述】:
我认为我对 C++ 相当了解,并且我正在考虑实现一些比“玩具”程序更大的东西。我知道堆栈内存和堆内存与 RAII 习语之间的区别。
假设我有一个简单的类point:
class point {
public:
int x;
int y;
point(int x, int y) : x(x), y(y) {}
};
我总是在堆栈上分配点,因为对象很小。由于在 64 位机器上sizeof(point) == sizeof(void*),如果没有错,我会走得更远,默认按值传递分数。
现在让我们假设一个更复杂的类battlefield,我想在类game中使用它:
class battlefield {
public:
battlefield(int w, int h, int start_x, int start_y, istream &in) {
// Complex generation of a battlefield from a file/network stream/whatever.
}
};
因为我真的很喜欢 RAII 和对象离开作用域时的自动清理,所以我很想在堆栈上分配战场。
game::game(const settings &s) :
battlefield(s.read("w"), s.read("h"), gen_random_int(), gen_random_int(), gen_istream(s.read("level_number"))) {
// ...
}
但我现在有几个问题:
由于这个类没有零参数构造函数,我必须在我使用战场的类的初始化列表中对其进行初始化。这很麻烦,因为我需要来自某个地方的 istream。这导致了下一个问题。
复杂的构造函数有时会“滚雪球”。当我在game类中使用battlefield并在game的构造函数的初始化列表中初始化它时,游戏的构造函数也会变得相当复杂game 本身的初始化也可能变得很麻烦。 (当我决定将 istream 作为 game 构造函数的参数时)
我需要辅助函数来填写复杂的参数。
我看到了这个问题的两种解决方案:
-
我为 battlefield 创建一个简单的构造函数,它不会初始化对象。但是这种方法的问题是我有一个半初始化的对象,也就是一个违反 RAII 习惯用法的对象。在这样的对象上调用方法时可能会发生奇怪的事情。
game::game(const settings &s) { random_gen r; int x = r.random_int(); int y = r.random_int(); ifstream in(s.read("level_number")); in.open(); this->battlefield.init(s.read("w"), s.read("h"), x, y, in); // ... } -
或者我在 game 构造函数的堆上分配 battlefield。但我必须小心构造函数中的异常,我必须注意析构函数会删除 battlefield。
game::game(const settings &s) { random_gen r; int x = r.random_int(); int y = r.random_int(); ifstream in(s.read("level_number")); in.open(); this->battlefield = new battlefield(s.read("w"), s.read("h"), x, y, in); // ... }
我希望你能看到我正在考虑的问题。我遇到的一些问题是:
我不知道这种情况有设计模式吗?
大型 C++ 项目的最佳实践是什么?哪些对象在堆上分配,哪些在栈上分配?为什么?
关于构造函数复杂性的一般建议是什么?对于构造函数来说,从文件中读取太多了吗? (因为这个问题主要是由复杂的构造函数引起的。)
【问题讨论】:
-
顺便说一下,您在这里使用的术语“堆栈”具有误导性;当您创建一个对象作为另一个类的成员时,您不是在堆栈上分配它,而是在分配父对象的任何地方。如果
battlefield分配在堆上(C++ 术语中的“freestore”),那么它的所有子对象都将在堆上。 -
“因为在 64 位机器上 sizeof(point) == sizeof(void*), if a am not wrong” - 你是错了;
int保证为至少 32 位类型,但它完全由实现定义。它也可以是 64 位的。此外,“堆栈”和“堆”在 C++ 标准中没有定义;您想提到“自动”和“动态”存储,因为堆栈和堆是实现细节。 -
"
int保证至少为 32 位" - 真的吗?
标签: c++ memory-management raii