对象已在声明中初始化?

时间:2010-08-17 20:48:21

标签: c++

我试图用C ++来理解某些东西。基本上我有这个:

class SomeClass {
    public:
        SomeClass();
    private:
        int x;
};

SomeClass::SomeClass(){
    x = 10;
}

int main() {
    SomeClass sc;
    return 0;
}
我认为sc是SomeClass类型的未初始化变量,但是从各种教程中我发现它看起来像这个声明实际上是一个调用SomeClass()构造函数的初始化,而我不需要调用“sc = new SomeClass”( );”或类似的东西。

当我来自C#世界(并且知道一点C,但没有C ++)时,我试图理解什么时候我需要像new这样的东西以及什么时候发布这样的对象。我发现了一种名为RAll的模式似乎与此无关。

这种类型的初始化调用是什么,如何知道某些内容是仅仅声明还是完全初始化?

5 个答案:

答案 0 :(得分:18)

答案 1 :(得分:3)

您在main()的第一行中所做的是在堆栈上分配SomeClass对象。而new运算符则在堆上分配对象,并将指针返回给类实例。这最终通过.(使用实例)或使用->(使用指针)导致两种不同的访问技术

由于你知道C,所以每次你说时都会执行堆栈分配,例如int i;。另一方面,堆分配在C中使用malloc()执行。 malloc()返回一个指向新分配空间的指针,然后将其转换为指向某个东西的指针。例如:

int *i;
i = (int *)malloc(sizeof(int));
*i=5;

虽然在堆栈上分配的东西的释放是自动完成的,但是在堆上分配的东西的解除分配必须由程序员完成。

你混淆的根源来自于C#(我不使用,但我知道它与Java类似)没有堆栈分配。当你说SomeClass sc时,你所做的就是声明一个SomeClass引用,这个引用当前是未初始化的,直到你说new,这是对象弹出的时刻。在new之前,你没有任何对象。在C ++中,情况并非如此。 C ++中没有类似于C#(或java)的引用概念,尽管在函数调用期间只有C ++中的引用(在实践中它是一个传递引用的范例。默认情况下,C ++按值传递,意味着你在函数调用时复制对象)。然而,这不是全部。查看评论以获得更准确的详细信息。

答案 2 :(得分:2)

在您的情况下,使用sc的默认构造函数在堆栈上分配SomeClass。由于它在堆栈上,因此从函数返回时将破坏实例。 (如果在从SomeClass sc调用的函数中实例化main,这将更令人印象深刻 - 分配给sc的内存在返回main时将被取消分配。)< / p>

new关键字,而不是在运行时堆栈上分配内存,在堆上分配内存。由于C ++没有自动垃圾收集,因此您(程序员)负责取消分配您在堆上分配的任何内存(使用delete关键字),以避免内存泄漏。

答案 3 :(得分:2)

当您在函数范围内声明变量(不包含extern)时(例如在main中),您还定义了变量。该变量在到达声明时出现,并在其范围结束时(在本例中为函数main的结尾)不存在。

当一个对象存在时,如果它有一个用户声明的构造函数,那么它的一个构造函数用于初始化它。类似地,如果它具有用户声明的析构函数,则当对象超出范围以在超出范围时执行任何所需的清理操作时,将使用此方法。这与具有可能会或可能不会运行的终结器的语言不同,当然也不是在确定的时间点。它更像using / IDisposable

在C ++中使用new表达式来动态创建对象。它通常用于对象的生命周期不能绑定到特定范围的地方。例如,在创建它的函数完成后它必须继续存在。它也用于现在在编译器时知道要创建的对象的确切类型的情况,例如,在工厂功能。在许多情况下,通常可以避免动态创建对象,因为它们通常用于Java和C#等语言中。

使用new创建对象时,必须在某个时刻通过delete表达式销毁它。为了确保程序员不要忘记这样做,通常使用某种智能指针对象来自动管理它,例如,来自tr1或者提升的shared_ptr

答案 4 :(得分:2)

其他一些答案基本上告诉你“sc在堆栈上分配,new在堆上分配对象”。我不想以这种方式考虑它,因为它将实现细节(堆栈/堆)与代码的语义混为一谈。既然你习惯了C#做事的方式,我认为它也会产生歧义。相反,我更喜欢考虑它的方式是C ++标准描述它的方式:

sc是SomeClass类型的变量,在块作用域中声明(即构成主函数的大括号)。这称为局部变量。由于未声明staticextern,因此它具有自动存储持续时间。这意味着每当执行行SomeClass sc;时,变量将被初始化(通过运行其构造函数),当变量超出范围时退出块,它将被销毁(通过运行其析构函数) - 因为你没有,而你的对象是普通的旧数据,所以不会做任何事情。)

之前我曾说过“因为它没有声明staticextern”,如果您已经声明它,那么它将具有静态存储持续时间。它将在程序启动之前初始化(技术上在块范围内,它将在首次使用时初始化),并在程序终止后销毁。

使用new创建对象时,可以使用动态存储持续时间创建对象。当您致电new时,此对象将被初始化,并且只有在您呼叫delete时才会销毁此对象。要调用delete,您需要维护对它的引用,并在完成对象使用后调用delete。编写良好的C ++代码通常不会非常使用这种类型的存储持续时间,而是通常将值对象放入容器(例如std::vector)中,这些容器管理包含值的生命周期。容器变量本身可以进入静态存储或自动存储。

希望这有助于消除歧义,不会滥用太多新条款,以免让您感到困惑。