我正在读一本书,它说 in 的内置类型的初始化和赋值之间没有区别C
or C++
,但是 in 之类的类型string
却有C++
区别。为什么?为什么内置类型没有区别C
?
5 回答
因为标准类型int
没有构造函数。这些
int x = 123;
int y;
y = 123;
是相同的(一开始,y
会有一些随机/垃圾值)。
在创建对象时会调用其构造函数。因此,例如:
std::string s = "123";
std::string y;
y = "123";
s
将立即创建并初始化,而y
将被创建,其值将被初始化(基于std::string
的构造函数),稍后,它们将在operator=
.
C 并没有真正区分初始化和赋值;在 C 中,第一个赋值可以被认为是初始化,并且:
int a = 42;
和
int a;
a = 42;
基本相同。
在 C++ 中,初始化和赋值是不同的,即使对于最基本的类型也是如此。考虑:
int
main( int argc, char** argv )
{
switch ( argc ) {
case 1:
int a = 42;
// ...
break;
default:
// ...
}
}
这在 C++ 中是非法的。另一方面:
int
main( int argc, char** argv )
{
switch ( argc ) {
case 1:
int a;
a = 42;
// ...
break;
default:
// ...
}
}
是合法的。规则是没有代码可以“跳过”初始化到变量仍在范围内的点,但它可以跳过不包含初始化的定义。
当然,很难想象编译器会为 a 的初始化和赋值生成不同的代码int
,但它们在形式上仍然是不同的。
Kiril Kirov已经解释了为什么标准类型的初始化和赋值是相同的,但是我想给你一个实际的例子,什么时候调用什么,所以让我们玩一下:
#include <iostream>
using std::cout;
using std::endl;
class A {
protected:
int x;
public:
A()
{
cout << "Constructor" << endl;
}
A(int val)
{
x = val;
cout << "Parametrized constructor with x=" << x << endl;
}
A(const A& o)
{
cout << "Copy constructor with x=" << o.x << endl;
x = o.x;
}
~A()
{
cout << "Destructor for x=" << x << endl;
}
A &operator=(int val)
{
cout << "Assigning value x=" << val << endl;
x = val;
return *this;
}
A &operator=(const A& o)
{
// You are required to free previously allocated resources
// if you're not going to reuse them
cout << "Assigning value from parent object x=" << o.x << endl;
x = o.x;
return *this;
}
};
int main()
{
A a = 1;
A b;
b = 2;
A c = a;
b = a;
A d(4);
cout << endl;
return 0;
}
将导致:
Parametrized constructor with x=1
Constructor
Assigning value x=2
Copy constructor with x=1
Assigning value from parent object x=1
Parametrized constructor with x=4
Destructor for x=4
Destructor for x=1
Destructor for x=1
Destructor for x=1
所以总结一下:
A a = 1;
- 将调用参数化构造函数A b;
- 将调用空构造函数b = 2;
- 将调用赋值运算符A c = a;
- 将调用复制构造函数b = a;
- 将调用分配对象运算符A d(4);
- 将调用参数化构造函数
C++ 的内置原语都具有非常简单的结构:每个都存储在单个连续的内存块中。要初始化或分配这样的原语,您需要将整个新值的内容复制到原语占用的内存区域中。无需其他操作。旧值总是被此操作破坏,无论是先前分配的值还是留在内存未初始化部分的垃圾。
另一方面,类可能具有非常复杂的结构。它们可能具有指向其他对象的指针,并持有在为该类的对象分配新值时需要释放的资源。当您执行初始化时,您知道该对象还没有持有其他对象或资源,因此不需要释放任何东西。但是,当您分配现有对象时,可能需要释放它所拥有的资源和对象。这就是为什么分配不同于非基元的初始化。
标准数据类型没有构造函数。所以当你说,
int a = 2;
那么一个变量的值为 2。
当你说,
int b;
b = 5;
然后当 b 被创建时,它将有一些垃圾值,稍后它将被分配新值,即 5。
这不是 std::string 的情况。因为它有构造函数,所以当你创建一个类字符串的对象时,它将使用它的构造函数创建。
string str = "sample";
str
将使用字符串的参数化构造函数使用值样本创建。
string str1;
str1 = "sample2";
str1
将使用 string 的默认构造函数创建为空字符串,然后使用 string 的赋值运算符分配新值。