【问题标题】:Is there any difference between struct Data d = {0} and struct Data d = {}struct Data d = {0} 和 struct Data d = {} 之间有什么区别吗
【发布时间】:2017-04-07 00:44:02
【问题描述】:

我的代码中有两种类型的结构变量初始化。

例子

#include<iostream>
#include<string>
using namespace std;
struct Data{
   int arr[5];
   float x;

};
int main(){
   struct Data d = {0};
   struct Data d1 = {};
   cout<<d.arr[0]<<d.x;
   cout<<d1.arr[0]<<d1.x<<endl;
   return 0;
}

我正在运行代码广告,得到 0 0 0 0 作为我的输出。请帮帮我,这两种初始化有什么区别。

【问题讨论】:

  • 一个是你拥有的初始化列表,另一个只是一个空的初始化列表。
  • 你希望每个里面有什么?你不应该这样初始化你的结构。您需要访问结构中的每一件事并对其进行初始化。可能有一个函数,它接受一个结构并有一个 for 循环,将数组中的所有内容初始化为 0,将 x 初始化为 0
  • @Danh 不要混蛋。将问题标记为c,因为它涉及 c 和 c++ 共有的语法是不正确的,但它不是“垃圾邮件”。

标签: c++ struct initialization aggregate-initialization


【解决方案1】:

根据aggregate initialization的规则,这里的效果是一样的,即struct的所有成员都是value-initialized(这里zero-initialized是非类类型)。

如果初始化子句的数量小于成员and bases (since C++17)或初始化列表完全为空,则其余成员and bases (since C++17)由空列表初始化by their default initializers, if provided in the class definition, and otherwise (since C++14),按照通常的列表初始化规则(它使用默认构造函数对非类类型和非聚合类执行值初始化,并为聚合执行聚合初始化)。如果引用类型的成员是这些剩余成员之一,则程序是非良构的。

更准确地说,

struct Data d = {0}; // initialize the 1st member of Data to 0, value-initialize(zero-initialize) the remaining members
struct Data d1 = {}; // value-initialize(zero-initialize) all the members of Data

注意整个故事是基于Data是一个aggregate type并且它的成员是非类类型,否则行为会根据list initialization的规则改变。

【讨论】:

  • 我觉得Data有构造函数时的效果值得一提
  • 如果Data的第一个成员是类类型也会有所不同
【解决方案2】:

是的,有区别。在第一种情况下,您将Data (arr[0]) 的第一个成员显式初始化为零。在第二种情况下,您没有初始化任何东西,而只是读取碰巧存在的任何值。在这种情况下,它也为零,但不能保证有效,尤其是在更复杂的程序中。

初始化结构的所有成员总是一个好主意。考虑一下您的程序的这个稍微修改过的版本,它应该可以清楚地说明正在发生的事情:

#include<iostream>
#include<string>
using namespace std;
struct Data{
   int arr[5];
   float x;
};
int main(){
   struct Data d = {1, 2, 3, 4, 5, 3.14f};
   struct Data d1 = {};
   cout<<d.arr[0]<<", "<<d.x<<", ";
   cout<<d1.arr[0]<<", "<<d1.x<<endl;
   return 0;
}

这将打印:

1, 3.14, 0, 0

【讨论】:

  • 你的程序应该说明什么?
【解决方案3】:

使用{}的默认初始化定义为使用{}初始化每个成员。所以,通过做

struct Data d1 = {};

Data d1被初始化为{{},{}},也就是{{0, 0, 0, 0, 0}, 0.0}

00.0 分别是 intfloat 的默认值。

这就是您看不到任何差异的原因。在你的情况下,他们俩总是做同样的事情。

不同之处在于:

1.) 这是在 {} 内提供初始化程序时强制

struct X {
    X(int);
};

X  x1 {};    // error : empty initializer. X(int) states that an int is required to construct an X.
X  x2 {0};   // OK

2.) 零初始化被禁止的场景:

struct Test {
    string name;
    int year;
};
Test alpha0{0}; // Error. Because name in Test fails at zero-initialization.
Test alpha{};     // OK. Because name in Test is default-initialized with empty string "".

【讨论】:

    【解决方案4】:

    在这种情况下结果是相同的,但在其他情况下不一定如此。

    在这种情况下,您没有提供 ctor,因此您正在使用聚合初始化。这为空初始化列表提供了零初始化,并且您为非空列表提供了 0,因此两者的结果相同。

    如果您提供了一个 ctor,那么从两者中获得不同的结果将是微不足道的:

    #include <iostream>
    
    struct foo {
        int f;
    
        foo(int f = 5) : f(f) {}
        friend std::ostream &operator<<(std::ostream &os, foo const &f) { 
            return os << f.f;
        }
    };
    
    int main() { 
    
        foo f1{};
        foo f2{0};
    
        std::cout << "Empty init list: " << f1 << "\n";
        std::cout << "zero init list: " << f2 << "\n";
    }
    

    虽然 ctor 是最明显的方法,但它并不是唯一的方法。另一个明显的例子(仅限 C++11 和更新版本):

    struct foo { 
        int f = 5;
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-24
      • 2011-11-14
      • 1970-01-01
      • 2016-11-01
      • 1970-01-01
      • 2014-06-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多