C语言 initialization和assignment有什么区别?

deyfvvtc  于 2023-10-16  发布在  其他
关注(0)|答案(6)|浏览(137)

initialization和assignment有什么区别?
我对以下声明感到困惑:
C提供了另一种初始化成员变量的方法,允许我们在创建成员变量时初始化成员变量,而不是在创建之后。这是通过使用初始化列表来完成的。使用初始化列表与进行隐式赋值非常相似。
PS:C/C
示例值得赞赏。

lymnna71

lymnna711#

哦,天哪。任务和任务。那肯定是混淆了!

initialize是准备使用。当我们谈论一个变量时,这意味着 * 给变量一个第一个有用的值 *。其中一种方法是使用赋值。

所以这是相当微妙的:赋值是进行初始化的一种方法。
赋值对于初始化很有效,例如:一个int,但是它不能很好地初始化,例如。a std::string .因为std::string对象至少包含一个指向动态分配内存的指针,

  • 如果对象尚未初始化,则需要将该指针设置为指向正确分配的缓冲区(用于保存字符串内容的内存块),但
  • 如果对象已经被初始化,则赋值可能必须释放旧的缓冲区并分配新的缓冲区。

因此std::string对象的赋值操作符显然必须以两种不同的方式运行,这取决于对象是否已经初始化!
当然,它不会以两种不同的方式表现。相反,对于std::string对象,初始化由构造函数负责。你可以说构造函数的工作是获取内存中表示对象的区域,并将其中的任意位更改为适合对象类型的内容,即表示有效对象状态的内容。
从 * 原始内存 * 初始化理想情况下应该为每个对象做一次,在对象上的任何其他操作之前。
而C规则有效地保证了这一点。至少只要你不使用非常低水平的设施。有人可能会称之为**C构造保证**。
所以,这意味着当你这样做的时候,

std::string s( "one" );

那么你就是在从原始内存中进行简单的构造,但当你这样做时,

std::string s;
    s = "two";

然后你首先构造s(用一个对象状态表示一个空字符串),然后赋值给这个已经初始化的s
最后,我可以回答你的问题。从语言独立编程的Angular 来看,第一个有用的值大概是被赋值的值,因此在这种观点中,人们认为赋值是初始化。然而,在C++技术层面上,初始化已经通过调用std::string的默认构造函数完成了,所以在这个层面上,人们认为声明是初始化,赋值只是后来对值的更改。
因此,特别是术语“初始化”取决于上下文!
简单地运用一些常识来整理别人可能意味着什么。
干杯,

pgpifvop

pgpifvop2#

简单来说:

int a = 0;  // initialization of a to 0
a = 1;      // assignment of a to 1

对于内置的类型,它相对简单。对于用户定义的类型,它可以变得更复杂。查看this article.
例如:

class A
{
public:
   A() : val_(0)  // initializer list, initializes val_
   {}

   A(const int v) : val_(v) // initializes val_
   {}

   A(const A& rhs) : val_(rhs.val_)  // still initialization of val_
   {}

private:
    int val_;
};

// all initialization:
A a;
A a2(4);
A a3(a2);

a = a3; // assignment
hmae6n7t

hmae6n7t3#

示例正在创建一个示例(类型),该示例具有一定的值。

int i = 0;

赋值是对已经创建的示例(类型)进行给予。

int i;
i = 0

回答您编辑的问题:

***在构造函数中初始化和赋值有什么区别?&

有什么好处呢?***
使用初始化器列表初始化成员和在构造函数体内为其赋值之间存在差异。
当你通过初始化器列表初始化字段时,构造函数将被调用一次。
如果你使用赋值,那么字段将首先用默认构造函数初始化,然后用实际值重新赋值(通过赋值运算符)。
正如你所看到的,在后者中有一个额外的创建和赋值开销,这对于用户定义的类来说可能是相当大的。
对于整数数据类型或POD类成员,没有实际的开销。

代码示例:

class Myclass
{
public: 
 Myclass (unsigned int param) : param_ (param)
 {
 }

unsigned int param () const
{
     return param_;
}

private:
     unsigned int param_;
};

在上面的例子中:

Myclass (unsigned int param) : param_ (param)

这个构造在C++中称为成员初始化列表
它将成员param_**转换为值param

  • HAVE TO何时使用成员初始化器列表?***

如果出现以下情况,您将不得不(被迫)使用成员初始化程序列表:
您的类有一个引用成员
你的类有一个const成员或者
您的类没有默认构造函数

wixjitnu

wixjitnu4#

初始化:给一个对象一个初始值:

int a(0);
int b = 2;
int c = a;
int d(c);
std::vector<int> e;

赋值:为一个对象赋值:

a = b;
b = 5;
c = a;
d = 2;
um6iljoc

um6iljoc5#

在C中,初始化的一般语法是{}

struct toto { unsigned a; double c[2] };
struct toto T = { 3, { 4.5, 3.1 } };
struct toto S = { .c = { [1] = 7.0 }, .a = 32 };

用于S的初始化器被称为“指定初始化器”,并且仅从C99开始可用。

  • 省略的字段会自动初始化为相应类型的正确0
  • 此语法甚至适用于基本数据类型,如double r = { 1.0 };
  • 有一个catchall初始化器将所有字段设置为0,即{ 0 }
  • 如果变量是静态连接,则初始化器的所有表达式必须是常量表达式

这种{}语法不能直接用于赋值,但在C99中,您可以使用复合文字,如

S = (struct toto){ .c = { [1] = 5.0 } };

所以首先在RHS上创建一个临时对象,并将其分配给您的对象。

dpiehjr4

dpiehjr46#

有一件事还没有人提到,那就是构造函数中类字段的初始化和赋值之间的区别。
让我们来看看这个类:

class Thing
{
  int num;
  char c;
public:
  Thing();
};

Thing::Thing()
  : num(5)
{
  c = 'a';
}

我们这里有一个构造函数,它将Thing::num初始化为值5,并将'a'赋给Thing::c。在这种情况下,差异很小,但是正如前面所说的,如果你要在这个例子中用intchar来替换一些任意的类,我们将讨论调用参数化构造函数与调用默认构造函数后跟operator=函数之间的区别。

相关问题