如何初始化一个以结构为值的地图?

时间:2010-12-09 09:18:32

标签: c++ map struct initialization associative-array

我使用地图作为ID的关联数组 - > value,其中value是定义对象的结构:

#include <map>

struct category {
        int id;
        std::string name;
};

std::map<int, category> categories;

int main() {
        categories[1] = {1, "First category"};
        categories[2] = {2, "Second category"};

}

上面的代码用g ++编译,但有以下警告:

warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x

我已经阅读了有关结构初始化的各种问题/答案,但我仍然有点困惑。我有一系列相关问题:

  1. 我可以添加编译器选项-std = c ++ 0x并完成警告,但仍然没有关于底层问题的明智之处。如果我在类别struct中添加一个方法会不会破坏?

  2. 以更符合C ++ 03的方式初始化此POD结构(类别)的最佳方法是什么?

  3. 基本上,我还不确定以某种方式而非另一种方式做事的后果。这种关联数组(其中键是对象的ID)很容易用PHP,我仍然在学习在C ++中使用它的正确方法。在上面的代码中是否有任何我应该注意的事项?

  4. 修改
    以下问题是相关的,但是当我第一次阅读时我不明白答案:
    C++ initialize anonymous struct
    c++ Initializing a struct with an array as a member
    Initializing structs in C++

5 个答案:

答案 0 :(得分:20)

在C ++(ISO / IEC 14882:2003)中,括号括起的表达式列表可用于在定义它的声明中初始化 aggregate 类型的变量。

E.g。

struct S { int a; std::string b; };

S x = { 39, "Hello, World\n" };

聚合类型是一个数组或类,没有用户声明的构造函数,没有私有或受保护的非静态数据成员,没有基类,也没有虚函数。请注意,类聚合不必是POD类,任何数组都是聚合,无论它是数组的类型是聚合。

但是,括号括起的表达式列表仅作为聚合的初始值设定项有效,通常不允许在其他上下文中使用,例如赋值或类构造函数的成员初始化列表。

在下一版C ++(C ++ 0x)的当前草案中,在更多上下文中允许括号括起的表达式列表( brace-init-list ),当一个对象是从这样的初始化列表初始化,它被称为 list-initialization

允许这样的列表的新上下文包括函数调用中的参数,函数返回,构造函数的参数,成员和基本初始化器以及赋值的右侧。

这意味着这在C ++ 03中无效。

int main() {
        categories[1] = {1, "First category"};
        categories[2] = {2, "Second category"};
}

相反,你可以这样做。

int main() {
        category tmp1 = { 1, "First category" };
        category tmp2 = { 2, "Second category" };

        categories[1] = tmp1;
        categories[2] = tmp2;
}

可替换地。

int main() {
        category tmpinit[] = { { 1, "First category" },
                               { 2, "Second category" } };
        categories[1] = tmpinit[0];
        categories[2] = tmpinit[1];
}

或者,您可以考虑为您的类型制作工厂功能。 (您可以为您的类型添加构造函数,但这会使您的类成为非聚合,并且会阻止您在其他位置使用聚合初始化。)

category MakeCategory( int n, const char* s )
{
    category c = { n, s };
    return c;
}

int main()
{
    categories[1] = MakeCategory( 1, "First category" );
    categories[2] = MakeCategory( 2, "Second category" );
}

答案 1 :(得分:10)

在当前的C ++标准中,您可以使用初始化列表来初始化仅包含POD值的数组和结构。下一个标准(又名C ++ 0x或C ++ 1x)将允许在包含非POD类型的结构上执行相同的操作,例如:的std :: string。这就是警告的内容。

我建议你为category添加一个简单的构造函数,它接受id和name,然后简单地调用该构造函数:

#include <map>
#include <string>

struct category {
        category() : id(0), name() {}
        category(int newId, std::string newName)
         : id(newId), name(newName) {}

        int id;
        std::string name;
};

std::map<int, category> categories;

int main() {
        categories[1] = category(1, "First category");
        categories[2] = category(2, "Second category");

}

答案 2 :(得分:3)

我们正在使用的初始化类型仅在新兴的C ++标准C ++ 0x中引入,因此是警告和编译器选项。一些编译器,如g ++,已经支持一些新功能,但标准本身尚未被接受。它为我们所知道的C ++增加了许多新功能。您可以在Stroustrup's site上阅读更多内容。

初始化您可以添加ctor(自然)的结构,例如

struct category {
        category(int i, const std::string& n): id(i), name(n) {}
        int id;
        std::string name;
};

然后按如下方式初始化地图:

categories[1] = category(1, "First category");

请注意,从const char*到字符串的隐式转换可以在此处使用,否则您也可以使用const char*定义ctor。

答案 3 :(得分:1)

您需要的功能在C / C ++中称为聚合。通过搜索“聚合c ++”,你会发现很多信息,详细说明了这些原因和方法。

  

1-如果我添加一个,不会破坏   类别struct的方法?

除非该方法影响底层C ++内存布局,否则没有必要。例如,普通函数无关紧要,但虚函数会因为它可能在类成员之前布局。

  

2-最好的方式是什么   初始化此POD结构(类别)   以更符合c99的方式?

使用构造函数作为其他响应者的建议。

  

3-我应该支付任何费用   注意在上下文中   上面的代码?

根据您设计构造函数的方式,它可能涉及冗余副本。但只有你经常需要初始化并且你真的关心性能才会很重要。

答案 4 :(得分:1)

我知道这很旧,但是也可以使用

std::map<int, std::pair<std::string, int>> categories

或:

std::map<int, std::tuple<std::string, int, double>> categories

如果需要更多。