C++结构初始化

Din*_*.R. 259 c++

是否可以在C++中初始化结构,如下所示

struct address {
    int street_no;
    char *street_name;
    char *city;
    char *prov;
    char *postal_code;
};
address temp_address =
    { .city = "Hamilton", .prov = "Ontario" };
Run Code Online (Sandbox Code Playgroud)

这里这里的链接提到可以仅在C中使用此样式.如果是这样,为什么在C++中这是不可能的?是否有任何潜在的技术原因导致它没有在C++中实现,或者使用这种风格是不好的做法.我喜欢使用这种初始化方式,因为我的结构很大,这种风格让我清楚地看到了为哪个成员分配了什么值.

如果有其他方法可以达到相同的可读性,请与我分享.

在发布此问题之前,我已经提到了以下链接

  1. C/C++ for AIX
  2. C变量的结构初始化
  3. 使用C++中的标记进行静态结构初始化
  4. C++ 11正确的结构初始化

Wyz*_*a-- 153

如果你想清楚每个初始化器的值是什么,只需将它分成多行,并对每个行进行注释:

address temp_addres = {
  0,  // street_no
  nullptr,  // street_name
  "Hamilton",  // city
  "Ontario",  // prov
  nullptr,  // postal_code
};
Run Code Online (Sandbox Code Playgroud)

  • 我不这样做,因为它很容易维护. (401认同)
  • 同意; C发明标记初始化是有充分理由的. (107认同)
  • 这样做有什么不同,实际上使用点符号来更准确地访问字段本身,它不像你正在节省任何空间,如果这是关注的问题.我真的不会让C++程序员在保持一致性和编写可维护的代码时,他们似乎总是想做一些不同的事情来使他们的代码脱颖而出,代码是为了反映问题得到解决它不应该是它本身就是一个成语,旨在提供可靠性和易维护性. (11认同)
  • 我个人喜欢并推荐这种风格 (6认同)
  • @ user1043000好吧,对于一个,在这种情况下,你放置你的成员的顺序是最重要的.如果在结构中间添加一个字段,则必须返回到此代码并查找插入新初始化的确切位置,这很难且很无聊.使用点表示法,您可以简单地将新的初始化放在列表的末尾,而不必担心订单.如果您碰巧在结构中添加相同类型(如`char*`)作为上面或下面的其他成员之一,那么点符号会更安全,因为没有交换它们的风险. (4认同)
  • 当您重命名字段时,注释不会改变,这是一个坏主意。 (4认同)
  • orip的评论.如果数据结构定义发生了变化,并且没有人认为要查找初始化,或者无法全部找到它们,或者编辑它们会出错,那么事情就会崩溃. (3认同)
  • 大多数(如果不是全部)POSIX结构没有定义的顺序,只有定义的成员。`(struct timeval){.seconds = 0,.microseconds = 100}`始终为一百微秒,但是`timeval {0,100}`可能为一百个_SECONDS_。您不想艰难地找到类似的东西。 (2认同)

Gui*_*i13 94

我的问题导致没有令人满意的结果后(因为C++没有为结构实现基于标记的init),我采用了我在这里找到的技巧:默认情况下,C++结构的成员是否初始化为0?

对你来说,这相当于:

address temp_address = {}; // will zero all fields in C++
temp_address.city = "Hamilton";
temp_address.prov = "Ontario";
Run Code Online (Sandbox Code Playgroud)

这肯定是最接近你想要的(除了你想要初始化的那些之外的所有字段都是零).

  • 这不适用于静态的本地化对象 (8认同)
  • `static address temp_address = {};`将起作用.之后填写它取决于运行时,是的.你可以通过提供一个为你执行init的静态函数来绕过这个:`static address temp_address = init_my_temp_address();`. (4认同)
  • 坏主意,它违反了 RAII 原则。 (3认同)
  • 非常糟糕的主意:在您的“地址”中添加一个成员,您将永远不会知道创建“地址”的所有地方,并且现在不初始化您的新成员。 (2认同)

sam*_*ari 16

正如其他人所说,这是指定的初始化程序.

此功能是C++ 20的一部分

  • 更多信息请参见:https://en.cppreference.com/w/cpp/language/aggregate_initialization (5认同)
  • @John 不是[根据 cppreference](https://en.cppreference.com/w/cpp/language/aggregate_initialization)。 (2认同)

Gen*_*ene 15

字段标识符确实是C初始化语法.在C++中,只需在没有字段名称的情况下以正确的顺序给出值.不幸的是,这意味着你需要全部给它们(实际上你可以省略尾随的零值字段,结果将是相同的):

address temp_address = { 0, 0, "Hamilton", "Ontario", 0 }; 
Run Code Online (Sandbox Code Playgroud)

  • @ DineshP.R.然后写一个构造函数! (7认同)
  • @MrLister(或任何人)也许我现在陷入了愚蠢的困境,但请注意解释构造函数如何更好?在我看来,向初始值设定项列表提供一堆依赖于顺序的未命名值或向构造函数提供一堆依赖于顺序的未命名值之间几乎没有区别......? (4认同)
  • 是的,目前我只使用这种方法(Aligned Struct Initialization).但我觉得可读性不好.由于我的结构很大,初始化程序有很多数据,我很难跟踪哪个值分配给哪个成员. (3认同)
  • @yano 说实话,我真的不记得为什么我认为构造函数可以解决问题。如果我记得的话,我会回到你身边。 (2认同)

小智 12

此功能称为指定的初始化程序.它是C99标准的补充.但是,这个功能被排除在C++ 11之外.根据The C++ Programming Language,第4版,第44.3.3.2节(C++未采用的C特性):

在C++中故意不采用C99(与C89相比)的一些补充:

[1]可变长度阵列(VLA); 使用矢量或某种形式的动态数组

[2]指定的初始化器; 使用构造函数

C99语法具有指定的初始化程序 [参见ISO/IEC 9899:2011,N1570委员会草案 - 2011年4月12日]

6.7.9初始化

initializer:
    assignment-expression
    { initializer-list }
    { initializer-list , }
initializer-list:
    designation_opt initializer
    initializer-list , designationopt initializer
designation:
    designator-list =
designator-list:
    designator
    designator-list designator
designator:
    [ constant-expression ]
    . identifier
Run Code Online (Sandbox Code Playgroud)

另一方面,C++ 11没有指定的初始化程序 [参见ISO/IEC 14882:2011,N3690委员会草案 - 2013年5月15日]

8.5初始化器

initializer:
    brace-or-equal-initializer
    ( expression-list )
brace-or-equal-initializer:
    = initializer-clause
    braced-init-list
initializer-clause:
    assignment-expression
    braced-init-list
initializer-list:
    initializer-clause ...opt
    initializer-list , initializer-clause ...opt
braced-init-list:
    { initializer-list ,opt }
    { }
Run Code Online (Sandbox Code Playgroud)

为了达到相同的效果,请使用构造函数或初始化列表:


run*_*ace 9

我可能在这里遗漏了一些东西,为什么不:

#include <cstdio>    
struct Group {
    int x;
    int y;
    const char* s;
};

int main() 
{  
  Group group {
    .x = 1, 
    .y = 2, 
    .s = "Hello it works"
  };
  printf("%d, %d, %s", group.x, group.y, group.s);
}
Run Code Online (Sandbox Code Playgroud)

  • @run_the_race,这是关于 c++ 标准所说的,而不是给定编译器的行为可能是什么。但是,此功能是在 c++20 中推出的。 (8认同)
  • 我使用 MinGW C++ 编译器和 Arduino AVR C++ 编译器编译了上述程序,并且都按预期运行。注意#include &lt;cstdio&gt; (2认同)

nik*_*ikc 8

你可以通过ctor初始化:

struct address {
  address() : city("Hamilton"), prov("Ontario") {}
  int street_no;
  char *street_name;
  char *city;
  char *prov;
  char *postal_code;
};
Run Code Online (Sandbox Code Playgroud)

  • 只有控制`struct address`的定义才是这种情况.此外,POD类型通常故意没有构造函数和析构函数. (8认同)

use*_*672 7

您甚至可以将Gui13的解决方案打包到单个初始化语句中:

struct address {
                 int street_no;
                 char *street_name;
                 char *city;
                 char *prov;
                 char *postal_code;
               };


address ta = (ta = address(), ta.city = "Hamilton", ta.prov = "Ontario", ta);
Run Code Online (Sandbox Code Playgroud)

免责声明:我不推荐这种风格


Fab*_*ian 7

我知道这个问题已经很老了,但我找到了另一种初始化方法,使用constexpr和currying:

struct mp_struct_t {
    public:
        constexpr mp_struct_t(int member1) : mp_struct_t(member1, 0, 0) {}
        constexpr mp_struct_t(int member1, int member2, int member3) : member1(member1), member2(member2), member3(member3) {}
        constexpr mp_struct_t another_member(int member) { return {member1, member,     member2}; }
        constexpr mp_struct_t yet_another_one(int member) { return {member1, member2, member}; }

    int member1, member2, member3;
};

static mp_struct_t a_struct = mp_struct_t{1}
                           .another_member(2)
                           .yet_another_one(3);
Run Code Online (Sandbox Code Playgroud)

此方法也适用于全局静态变量甚至constexpr变量.唯一的缺点是可维护性差:每次使用此方法必须初始化另一个成员时,必须更改所有成员初始化方法.

  • 这是[建造者模式](https://en.wikipedia.org/wiki/Builder_pattern)。成员方法可以返回对要修改的属性的引用,而不是每次都创建一个新的结构体 (2认同)

Pup*_*ppy 5

它没有在C++中实现.(还有,char*字符串?我希望不是).

通常,如果你有这么多参数,那就是相当严重的代码味道.但相反,为什么不简单地初始化结构然后分配每个成员?

  • 你可以使用`char*`但是`const char*`更加类型安全,每个人都只使用`std :: string`,因为它更可靠. (8认同)
  • *"(另外,`char*`字符串?我希望不会.)* - 嗯,这是一个C的例子. (6认同)
  • 他正在转向C++. (5认同)