我觉得这里有几件事情:
- 自动变量和对象的动态分配的变量
- 终身
- RAII
- C#平行
自动VS之间的区别动态
自动变量是系统管理寿命的变量。让我们抛弃全局变量的那一刻,它是复杂的,并且集中在通常情况下:
int main(int argc, char* argv[]) // 1
{ // 2
SomeClass sc; // 3
sc.foo(); // 4
return 0; // 5
} // 6
这里sc
是一个自动变量。在第(3)行成功完成之后,它保证被完全初始化(即构造函数保证已经运行)。它的析构函数将在第(6)行自动调用。
我们通常会谈到变量的范围:从声明点到相应的右括号;当范围退出时语言保证销毁,例如return
或例外。
当然,如果您调用可能导致崩溃的可怕“未定义行为”,当然不能保证。
另一方面,C++也有动态变量,即使用new
分配的变量。
int main(int argc, char* argv[]) // 1
{ // 2
SomeClass* sc = 0; // 3
sc = new SomeClass(); // 4
sc->foo(); // 5
return 0; // 6
} // 7 (!! leak)
这里sc
仍然是一个自动可变的,但是它的类型而有所不同:它现在是一个指针,指向SomeClass
类型的变量。
在线(3)sc
被分配了一个空指针值(在C++ 0x中为nullptr
),因为它没有指向SomeClass
的任何实例。请注意,该语言不保证自己进行任何初始化,因此您需要明确指定某些内容,否则您将拥有垃圾值。
在线(4)我们建立一个动态变量(使用new
算子)并将其地址分配给sc
。请注意,动态变量本身是未命名的,系统只给我们一个指针(地址)给它。
在线(7)系统自动销毁sc
,但它不会破坏它指向的动态变量,因此我们现在有一个动态变量,其地址不会存储在任何地方。除非我们使用垃圾收集器(这不是标准C++的情况),我们因此泄漏了内存,因为在过程结束之前变量的内存不会被回收......即使这样,析构函数也不会运行(太糟糕了,如果它有副作用)。对象
的
终身香草萨特对这个问题非常有趣的文章。这里是the first。
作为总结:
- 的对象,只要它的构造函数运行结束生命。这意味着如果构造函数抛出,对象永远不会存在(认为它是怀孕的意外)。
- 一旦析构函数被调用,一个对象就会死亡,如果析构函数抛出(这是EVIL)它不能被再次尝试,因为你不能在死对象上调用任何方法,这是未定义的行为。
如果我们回到第一个例子:
int main(int argc, char* argv[]) // 1
{ // 2
SomeClass sc; // 3
sc.foo(); // 4
return 0; // 5
} // 6
sc
是从线活着(4)到线(5)包容性。在线(3)正在构建(可能由于许多原因而失败)并且在线(6)正在被破坏。
RAII
RAII意味着资源获取就是初始化。这是一个管理资源的习惯用法,特别是要确保这些资源一旦被收购后最终将被释放。在C++中,由于我们没有垃圾收集,这个习惯用法主要应用于内存管理,但它也适用于任何其他类型的资源:多线程环境中的锁,文件锁,网络中的套接字/连接等...
当用于内存管理时,它用于将动态变量的生命周期与给定的一组自动变量的生命周期相耦合,确保动态变量不会超过它们(并且会丢失)。
在其最简单的形式,它耦合到单个自动变量:
int main(int argc, char* argv[])
{
std::unique_ptr<SomeClass> sc = new SomeClass();
sc->foo();
return 0;
}
它非常类似于第一实施例,不同之处在于我动态分配的SomeClass
一个实例。然后将此实例的地址交给sc
对象,其类型为std::unique_ptr<SomeClass>
(它是C++ 0x工具,如果不可用,则使用boost::scoped_ptr
)。 unique_ptr
保证当sc
被销毁时指向的对象将被销毁。
在一个更复杂的形式中,它可能会耦合到几个使用(例如)std::shared_ptr
的自动变量,顾名思义它允许共享一个对象并保证当最后一个共享者被销毁时该对象将被销毁。请注意,这不等同于使用垃圾回收器,并且可能存在引用循环的问题,因此我不会深入此处,因此只需记住std::shared_ptr
不是万能药。
因为它是非常复杂的异常和多线程代码的脸完全管理动态变量的寿命没有RAII的建议是:
- 使用自动变量尽可能
- 动态变量,从来没有对自己的调用
delete
,总是利用了RAII设施
我个人认为的delete
任何发生是强烈的怀疑,我送花儿给人要求在代码评论中删除它:这是一种代码味道。
C#并行
在C#中主要使用动态变量*
。这就是为什么:
- 如果你只需要声明一个变量,没有分配,其值为null:在本质上,你只指针进行操作,因此你有一个空指针(初始化保证,谢天谢地)
- 您使用
new
来创建值,这将调用您的对象的构造函数并产生对象的地址;注意语法与动态变量的C++类似
但是,与C++不同,C#是垃圾收集的,因此您不必担心内存管理。
被垃圾收集也意味着物体的寿命更难以理解:它们是在你要求它们时建立的,但是在系统方便时被破坏。这可能是实施RAII的一个问题,例如,如果您真的希望快速释放锁,并且该语言有一些设施可以帮助您从内存中获取关键字+ IDisposable
关键字+ IDisposable
。
*
:很容易检查,如果声明一个变量后其值为null
,那么它将是一个动态变量。我相信,对于int
的值将为0表示它不是,但已经3年了,因为我用C#拨弄了一个课程项目,所以...
“因为我来自C#世界”所以? C++不是C#,根本不了解C#。你需要一本[良好的初学者书](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list),你从头开始。 – GManNickG 2010-08-17 20:52:13
感谢您的名单!诚然,C++和C#是两种截然不同的语言。我想我只是不想了解什么是循环或类,更多的是关于它们如何在C++中工作,因此我一直在避免书籍。我会看看清单。 – 2010-08-17 20:58:33
@迈克尔:你无法避免书籍。 :) C++是它自己的语言。这听起来像你认为你已经理解了C++类,但它们与C#中的不一样。当然,你可能已经知道选择或迭代陈述了,但这只是一个章节。 – GManNickG 2010-08-17 21:00:34