我在网上浏览的时候看到了这个帖子,里面有这个
"(Well written) C++ goes to great
lengths to make stack automatic
objects work"just like" primitives,
as reflected in Stroustrup's advice to
"do as the ints do". This requires a
much greater adherence to the
principles of Object Oriented
development: your class isn't right
until it"works like" an int,
following the"Rule of Three" that
guarantees it can (just like an int)
be created, copied, and correctly
destroyed as a stack automatic."
我做过一点 C 和 C 代码,但只是顺带一提,从来没有什么严肃的事情,但我只是好奇,它到底是什么意思?
谁能举个例子?
堆栈对象由编译器自动处理。
当范围离开时,它被删除。
1 2 3
| {
obj a;
} // a is destroyed here |
当您对"新"对象执行相同操作时,您会遇到内存泄漏:
b 没有被破坏,所以我们失去了回收 b 拥有的内存的能力。更糟糕的是,对象无法自行清理。
在 C 中以下是常见的:
1 2 3 4 5
| {
FILE* pF = fopen( ... );
// ... do sth with pF
fclose( pF );
} |
在 C 中我们这样写:
1 2 3 4
| {
std::fstream f( ... );
// do sth with f
} // here f gets auto magically destroyed and the destructor frees the file |
当我们忘记在 C 示例中调用 fclose 时,文件不会关闭并且可能不会被其他程序使用。 (例如它不能被删除)。
另一个例子,演示对象字符串,它可以被构造、分配给并在退出范围时被销毁。
1 2 3 4 5 6 7
| {
string v("bob" );
string k;
v = k
// v now contains"bob"
} // v + k are destroyed here, and any memory used by v + k is freed |
除了其他答案:
C 语言实际上有 auto 关键字来显式声明对象的存储类。当然,完全没有必要,因为这是隐含的局部变量存储类,不能在任何地方使用。 auto 的反义词是 static(本地和全局)。
以下两个声明是等价的:
1 2 3 4
| int main() {
int a;
auto int b;
} |
因为关键字完全没用,它实际上会在下一个 C 标准(a€?C 0xa€?)中被回收并获得新的含义,即它让编译器从其初始化中推断变量类型(如C# 中的 var):
1
| auto a = std::max(1.0, 4.0); // `a` now has type double. |
如果我错了,请纠正我,但我认为复制操作对于充分利用自动堆栈清理并不是强制性的。
例如,考虑一个经典的 MutexGuard 对象,它不需要复制操作就可以作为堆栈自动使用,还是这样?
自动堆栈是分配在当前方法堆栈上的变量。设计一个可以充当 Stack 自动的类背后的想法是,应该可以通过一次调用完全初始化它并用另一个调用销毁它。析构函数必须释放对象分配的所有资源,并且其构造函数返回一个已完全初始化并准备好使用的对象。与复制操作类似——该类应该能够轻松地制作副本,这些副本功能齐全且独立。
此类的用法应该类似于原始int、float等的使用方式。你定义它们(最终给它们一些初始值)然后传递它们,最后让编译器进行清理。
C 中的变量既可以在栈上声明,也可以在堆上声明。当您在 C 中声明一个变量时,它会自动进入堆栈,除非您明确使用 new 运算符(它进入堆)。
1 2 3
| MyObject x = MyObject(params); // onto the stack
MyObject * y = new MyObject(params); // onto the heap |
这对内存的管理方式产生了很大的影响。当变量在堆栈上声明时,它将在超出范围时被释放。在对象上显式调用 delete 之前,堆上的变量不会被销毁。