关于 oop:C – “堆栈自动”是什么意思?

关于 oop:C – “堆栈自动”是什么意思?

C++ - What does "Stack automatic" mean?

我在网上浏览的时候看到了这个帖子,里面有这个

"(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

当您对"新"对象执行相同操作时,您会遇到内存泄漏:

1
2
3
{
    obj* b = new obj;
}

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 之前,堆上的变量不会被销毁。


推荐阅读