0

我问了一个问题,导致类实例化有些混乱。

如果您有一个 A() 类,例如:

class A
{
public:
    A();
    ~A();
};

然后我想和那个班级一起工作,可以完成以下所有工作:

// First way
A a1;
// Second way
A a1 = A();
// Third way
A::A a1 = A::A();
// Fourth way
A* a1 = new A();

有人告诉我第三种方式A::A a1 = A::A();不合适,但它似乎确实有效。

谁能解释所有这些方式以及何时使用其中一种方式?我认为new分配在堆而不是堆栈上?

示例程序:

#include <iostream>
#include <string>

class A
{
    public: 
    A();
    ~A();
};

A::A()
{
    std::cout << "A" << std::endl;
}

A::~A() {}

int main()
{   
     A a1;

    A a2 = A();

    A::A a3 = A::A();

    A* a4 = new A();

    return 0;
 }

输出:

$ ./test4
A
A
A
A

所以在 g++ 4.2 中它确实有效。

$ g++ -Wall main3.cpp -o test4
main3.cpp: In function ‘int main()’:
main3.cpp:28: warning: unused variable ‘a4’

在 gcc 4.8 中,没有那么多:

 g++-4.8 -std=c++11 -Wall main3.cpp -o test4
main3.cpp: In function ‘int main()’:
main3.cpp:26:2: error: ‘A::A’ names the constructor, not the type
 A::A a3 = A::A();
 ^
main3.cpp:26:7: error: expected ‘;’ before ‘a3’
  A::A a3 = A::A();
       ^
main3.cpp:26:18: error: statement cannot resolve address of overloaded function
  A::A a3 = A::A();
              ^
main3.cpp:28:8: warning: unused variable ‘a4’ [-Wunused-variable]
     A* a4 = new A();
        ^
4

3 回答 3

0

第一个a1使用默认构造函数进行初始化。

第二个首先a2使用默认构造函数进行初始化,然后将通过对默认构造函数的显式调用创建的对象分配给它。

我不认为第三种形式有效,所以我把它省略了。

最后一个分配适当大小的内存来存储类 A 的对象,并使用调用的构造函数(在您的情况下为默认构造函数)初始化分配的内存。

于 2013-06-01T23:29:01.960 回答
0

您应该了解动态分配和静态分配之间的区别。除此之外,第一种形式是您想要使用的,因为它隐式调用默认构造函数。在第二种形式中,您正在创建类 A 的临时实例并使用其自动生成的复制构造函数创建 a1,但是大多数编译器只会将其优化为 a1 的单个默认构造。第三种形式只是普通的无效 C++。第四种形式是执行动态分配,你没有用 delete 正确地释放你的内存,所以你把它留给你的操作系统在程序退出时回收内存。

于 2013-06-02T00:17:02.043 回答
0

对于您的对象,前两个版本是相同的(形式上,第二个版本包括另一个副本,但几乎任何值得其盐的编译器都对其进行了优化)。但是,有些对象并不相同:

如果您没有编写自己的默认构造函数(即使它是空的)并且对象没有静态存储时长(在您的代码中,它具有自动存储时长),第一个版本不会初始化任何 POD 成员,而第二个版本在任何情况下都会对它们进行零初始化。

另一方面,如果您的类不支持复制(您明确地将复制构造函数设为私有,或者在 C++11 中将其删除并且也没有提供移动构造函数),那么第二种形式将是错误的 -形成(即使副本实际上并没有发生,从逻辑上讲它就在那里)。

您的第三种形式不是合法的 C++;如果您的编译器接受它,那么它要么是错误,要么是非标准扩展(不过,我敢打赌)。

第四种形式进行动态分配,也就是说,您有责任再次明确地销毁它(使用delete a4;)。另请注意,存储在 a4 中的不是对象本身,而是指向它的指针;这意味着要访问对象,您必须显式取消引用指针。

请注意,从 C++11 开始,有一种新的初始化形式,尤其适用于空参数列表,因为它结合了前两个版本的优点:它也适用于不可复制/不可移动的对象,并且也初始化了 POD:

A a5{};
于 2013-06-02T00:30:26.913 回答