在C++中初始化一个指向结构体的指针数组

3
在C语言中,可以使用复合字面量来初始化指向结构体的指针数组。
typedef struct {
int a;
int b;
} s;

在C语言中:
s *ptrArray[] = {
    &(s){
        .a = 1,
        .b = 2
    },
    &(s){
        .a = 4,
        .b = 5
    }
};

如何用C++实现这个功能?

我也看到了C++中初始化结构体不使用复合语句的区别:

s s1 = { a: 7, b: 8 };

4
为什么你想要使用指针?为什么不想使用 std::vector<s> s1 = {{1,2}, {4,5}}; - t.niese
在C++中最好避免使用数组、指针和指针数组。 - n. m.
@n.m.:这需要一些参考链接或解释。 - einpoklum
@einpoklum 这些是非常低级的结构,类似于goto。这里没有太多可以解释的。 - n. m.
1
@n.m.:我认为你应该对新手提出的问题给予更具有教育性的评论。 - einpoklum
显示剩余5条评论
2个回答

2

首先,将任何东西初始化到临时值的地址似乎非常可疑,这在C语言中也是如此。你确定这是有效的吗?嗯。无论如何,C++编译器确实不会让你这样做。

至于你指定(命名字段)初始化C++行——它实际上是非标准的,是GNU C++扩展,你不能依赖它。

你可以这样做:

struct s { int a, b; };

int main() {
    s data[] = { { 1, 2 }, { 4, 5 } };
    // instead of ptrArray[i], use &(data[i])
}   

这段代码可以成功编译。但是,更符合C++语言风格的代码应该是:

#include <array>

struct s { int a, b; };

int main() {
    std::array<s, 2> data { s{ 1, 2 }, s{ 4, 5 } };
    // instead of ptrArray[i], use &(data[i]),
    // or use iterators, or ranged for loops
}   

为什么要使用 std::array这里有一篇解释其好处。实际上,您可以通过以下方式进一步减少重复:

int main() {
    auto data = make_array(s{ 1, 2 }, s{ 4, 5 });
    // instead of ptrArray[i], use &(data[i]),
    // or use iterators, or ranged for loops
}   
make_array函数的实现取自于这里。你还可以使用std::experimental::make_array(),但是它尚未被标准化。
如果你想在运行时添加或删除data中的元素,建议使用std::vector
#include <vector>

struct s { int a, b; };

int main() {
    std::vector<s> data { s{ 1, 2 }, s{ 4, 5 } };
    // instead of ptrArray[i], use &(data[i]),
    // or use iterators, or ranged for loops
}   

在C语言中,复合字面量的生命周期与局部变量相同,即具有包围块的生命周期。它们不具有C++临时对象的生命周期。值得注意的是,添加复合字面量的GNU C++扩展使用了C++临时对象的生命周期。 - Candy Gumdrop
@einpoklum 是的,抱歉让你感到困惑。 - n. m.
@CandyGumdrop:但是复合字面量是ptrArray的初始化程序,还是指针的初始化程序也被赋予整个程序的生命周期? - einpoklum
每个(type) { initializer }(C99复合字面量)表达式实际上都会创建一个新的匿名本地变量(如果在文件范围内创建,则为全局变量),因此像int *x = &(int) {123};这样取其中一个的地址是完全安全的,等同于int foo = 123; int *x = &foo;。 OP的示例相当于使用一些本地变量的地址初始化数组,这可以是完全有效的操作。 - Candy Gumdrop

1
你的初始化失败是因为你试图将指向结构体的指针数组初始化为数字文字常量的地址。就像这样:
#define A 5
int b = &A;    /* NOT HAPPENING */

(无法获取 5 的地址)

您可以通过初始化一个 s 数组而不是指向 s 的指针数组来解决问题,例如:

    s ptrarr[] = { {1, 2}, {4, 5} };

通过这个更改,你的数组将会正常初始化,例如:

#include <iostream>

typedef struct {
    int a;
    int b;
} s;

int main (void) {

    s ptrarr[] = { {1, 2}, {4, 5} };
    int cnt = 0;

    for (auto& i : ptrarr)
        std::cout << "ptrarr[" << cnt++ << "] : " << i.a << ", " << i.b << "\n";

}

例子使用/输出
$ ./bin/ptrarrystruct
ptrarr[0] : 1, 2
ptrarr[1] : 4, 5

OP在哪里获取数字字面常量的地址?C99复合字面量计算为具有封闭作用域寿命的lvalue。OP的示例是完全有效的C,只是使用了C++中不存在的语言特性。 - Candy Gumdrop
数字初始化程序不是复合字面量(省略了强制转换)。没有强制转换,您正在尝试初始化{ {1,2}, {4,5} }的地址,在C或C++中无法这样做。"初始化使指针从整数转换而来,没有强制转换"。 - David C. Rankin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接