C ++结构初始化

时间:2012-07-17 05:46:23

标签: c++

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

struct address {
    int street_no;
    char *street_name;
    char *city;
    char *prov;
    char *postal_code;
};
address temp_address =
    { .city = "Hamilton", .prov = "Ontario" };

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

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

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

  1. C/C++ for AIX
  2. C Structure Initialization with Variable
  3. Static structure initialization with tags in C++
  4. C++11 Proper Structure Initialization

17 个答案:

答案 0 :(得分:142)

如果你想明确每个初始值设定值是什么,只需将它分成多行,并对每个值进行评论:

address temp_addres = {
  0,  // street_no
  nullptr,  // street_name
  "Hamilton",  // city
  "Ontario",  // prov
  nullptr,  // postal_code
};

答案 1 :(得分:90)

my question导致结果不令人满意(因为C ++没有为结构实现基于标记的init),我采取了我在这里找到的技巧:Are members of a C++ struct initialized to 0 by default?

对你而言,这相当于:

address temp_address = {}; // will zero all fields in C++
temp_address.city = "Hamilton";
temp_address.prov = "Ontario";

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

答案 2 :(得分:13)

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

address temp_address = { 0, 0, "Hamilton", "Ontario", 0 }; 

答案 3 :(得分:12)

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

此功能是C++20

的一部分

答案 4 :(得分:11)

此功能称为指定的初始值设定项。它是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

另一方面,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 }
    { }

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

答案 5 :(得分: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);

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

答案 6 :(得分:7)

你可以通过ctor初始化:

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

答案 7 :(得分: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);

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

答案 8 :(得分:5)

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

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

答案 9 :(得分:3)

我在这里可能会缺少一些东西,为什么呢?

filterFn

答案 10 :(得分:2)

我发现这种方法可以用于全局变量,不需要修改原始结构定义:

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

然后声明从原始结构类型继承的新类型的变量,并使用构造函数进行字段初始化:

struct temp_address : address { temp_address() { 
    city = "Hamilton"; 
    prov = "Ontario"; 
} } temp_address;

虽然不像C风格那么优雅......

对于局部变量也应该是可能的,但需要检查是否需要额外的memset(this,0,sizeof(* this))然后......

(注意'temp_address'是'temp_address'类型的变量,但是这个新类型继承自'address',可以在每个需要'address'的地方使用,所以没关系。)

答案 11 :(得分:1)

这是可能的,但前提是您正在初始化的结构是POD(普通旧数据)结构。它不能包含任何方法,构造函数,甚至默认值。

答案 12 :(得分:1)

在C ++中,C样式初始值设定项被构造函数替换,编译器可以确保只执行有效的初始化(即初始化后对象成员是一致的)。

这是一个很好的做法,但有时候预先初始化很方便,就像在你的例子中一样。 OOP通过抽象类或creational design patterns来解决这个问题。

在我看来,使用这种安全方式会破坏简单性,有时安全权衡可能会过于昂贵,因为简单的代码不需要复杂的设计来保持可维护性。

作为替代解决方案,我建议使用lambdas定义宏以简化初始化,使其看起来几乎像C风格:

struct address {
  int street_no;
  const char *street_name;
  const char *city;
  const char *prov;
  const char *postal_code;
};
#define ADDRESS_OPEN [] { address _={};
#define ADDRESS_CLOSE ; return _; }()
#define ADDRESS(x) ADDRESS_OPEN x ADDRESS_CLOSE

ADDRESS宏扩展为

[] { address _={}; /* definition... */ ; return _; }()

创建并调用lambda。宏参数也以逗号分隔,因此您需要将初始化程序放入括号中并调用

address temp_address = ADDRESS(( _.city = "Hamilton", _.prov = "Ontario" ));

您还可以编写通用宏初始值设定项

#define INIT_OPEN(type) [] { type _={};
#define INIT_CLOSE ; return _; }()
#define INIT(type,x) INIT_OPEN(type) x INIT_CLOSE

然后这个电话稍微不那么漂亮了

address temp_address = INIT(address,( _.city = "Hamilton", _.prov = "Ontario" ));

但是您可以轻松地使用通用INIT宏来定义ADDRESS宏

#define ADDRESS(x) INIT(address,x)

答案 13 :(得分:0)

在GNUC ++中(很久以前似乎从2.5开始已经过时了:)请参见此处的答案:C struct initialization using labels. It works, but how?),可以初始化这样的结构:

JDK

答案 14 :(得分:0)

受到这个非常整洁的答案的启发:(https://stackoverflow.com/a/49572324/4808079

您可以进行lamba闭包:

// Nobody wants to remember the order of these things
struct SomeBigStruct {
  int min = 1;
  int mean = 3 ;
  int mode = 5;
  int max = 10;
  string name;
  string nickname;
  ... // the list goes on
}

class SomeClass {
  static const inline SomeBigStruct voiceAmps = []{
    ModulationTarget $ {};
    $.min = 0;  
    $.nickname = "Bobby";
    $.bloodtype = "O-";
    return $;
  }();
}

或者,如果您想变得很特别

#define DesignatedInit(T, ...)\
  []{ T ${}; __VA_ARGS__; return $; }()

class SomeClass {
  static const inline SomeBigStruct voiceAmps = DesignatedInit(
    ModulationTarget,
    $.min = 0,
    $.nickname = "Bobby",
    $.bloodtype = "O-",
  );
}

这涉及一些缺点,主要与未初始化的成员有关。从链接的答案注释中可以看出,尽管我没有测试过,但是它可以高效地编译。

总的来说,我只是认为这是一种整洁的方法。

答案 15 :(得分:0)

我今天遇到了类似的问题,我有一个结构,我想填充测试数据,它将作为参数传递给我正在测试的函数。我希望得到这些结构的向量,并且正在寻找一种初始化每个结构的单线方法。

我最终使用了结构中的构造函数,我相信在你的问题的一些答案中也会提出这个函数。

让构造函数的参数与公共成员变量具有相同的名称可能是不好的做法,需要使用this指针。如果有更好的方法,有人可以建议编辑。

typedef struct testdatum_s {
    public:
    std::string argument1;
    std::string argument2;
    std::string argument3;
    std::string argument4;
    int count;

    testdatum_s (
        std::string argument1,
        std::string argument2,
        std::string argument3,
        std::string argument4,
        int count)
    {
        this->rotation = argument1;
        this->tstamp = argument2;
        this->auth = argument3;
        this->answer = argument4;
        this->count = count;
    }

} testdatum;

我在我的测试函数中使用了以下各种参数来调用正在测试的函数:

std::vector<testdatum> testdata;

testdata.push_back(testdatum("val11", "val12", "val13", "val14", 5));
testdata.push_back(testdatum("val21", "val22", "val23", "val24", 1));
testdata.push_back(testdatum("val31", "val32", "val33", "val34", 7));

for (std::vector<testdatum>::iterator i = testdata.begin(); i != testdata.end(); ++i) {
    function_in_test(i->argument1, i->argument2, i->argument3, i->argument4m i->count);
}

答案 16 :(得分:-15)

你可以使用extern“C”来编译C ++中的c代码。在您的情况下,您可以使用以下代码

extern "C" {
//write your C code which you want to compile in C++
struct address {
int street_no;
char *street_name;`enter code here`
char *city;
char *prov;
char *postal_code;
};
address temp_address ={ .city = "Hamilton", .prov = "Ontario" };
}