在C++中传递固定大小的数组?

24

基本上我想做这样的事情:

int[3] array_func()
{
    return {1,1,1};
}

int main(int argc,char * argv[])
{
    int[3] point=array_func();
}

但在C++中似乎不合法。我知道可以使用向量,但由于我知道数组的大小是常量,所以似乎很可能会出现性能损失。 如果可能的话,我也想避免使用new,因为在堆栈上分配东西更容易,也有可能提高性能。

这里的解决方案是什么?


array_func()返回后,栈分配的数组将会丢失,对吧?因此,我认为这不是创建和返回数组的好方法。我认为最好在堆上分配它。附言:我不是C++专家,我只是写下了自己的看法。欢迎指正 :) - Doga Oruc
5个回答

31

使用 C++0x,即将正式发布的新 C++ 标准(已经实现在最新的 gcc 和 msvc 中,如果我没记错的话),你可以按照你想要的方式来完成任务!只需要使用 std::array 而不是 int[3]。

std::array<int, 3> array_func()
{
    return {1,1,1};
}

int main(int argc,char * argv[])
{
    std::array<int, 3> point = array_func();
}

22

将数组放入结构体中。boost::array就是这样一个工具包:

boost::array<int, 3> array_func() {
  boost::array<int, 3> a = {{ 1, 1, 1 }};
  return a;
}

int main() {
  boost::array<int, 3> b = array_func();
}

简单粗暴:

template<typename E, size_t S>
struct my_array {
  E data[S];
};

注意你可以使用聚合初始化语法。


我不明白为什么这个被点赞得这么多,使用标准语言特性(在这种情况下,一个简单的结构体)比调用boost更清晰和更快。虽然我推荐在这里使用模板化的结构体 - 这是最简单、最可重用的解决方案,也是我会做的事情。 - KomodoDave
@KomodoDave 你知道在我上面的代码片段中,你可以使用 sed, boost, std 而不需要 "一个简单的结构体" 吗?太好了,我们已经到了2011年!有时调用“臃肿的boost”(我猜)最终可能会比重新发明轮子更少地产生冗余。 - Johannes Schaub - litb
3
我建议对错误的答案和那些并没有真正回答问题的答案进行踩票。这个答案对我来说看起来还可以。 - jweyrich
我会点踩,因为我认为在这种情况下建议使用boost是一个糟糕的决定。如果唯一的建议是使用模板化结构体,那么这将是我首选的答案。 - KomodoDave
我认为对于模板化结构的正确使用,评论“快速而肮脏”是不恰当的。我的反对票与Johannes所说的“臃肿的boost”无关,事实上,我喜欢boost的一件事就是你只需要包含你需要的部分。我会忽略那个讽刺性的2011年评论,因为它对OP没有任何好处。 - KomodoDave

21

你可以将它包装在一个 struct 中,使其能够通过值进行返回:

struct Vec3
{
  float x[3];
}

Vec3 array_func()
{
  Vec3 x = { 1.f, 1.f, 1.f };

  return x;
}

我认为你不能直接在返回语句中使用数组初始化语法。当然,你可以引入一个构造函数(毕竟结构体只是所有成员都是公共的类):

struct Vec3
{
  Vec3(a, b, c)
  {
    x[0] = a;
    x[1] = b;
    x[2] = c;
  }

  float x[3];
}

Vec3 array_func()
{
  return Vec3(1.f, 1.f, 1.f);
}

4
除了这样的结构已经存在于https://dev59.com/jnI-5IYBdhLWcg3woJ9J之外,这将是最好的答案。 - sbi
8
我选择这个答案作为最佳答案,因为它直接回答了我的问题,没有推荐我没有要求的库。并不是说litb的答案不好,只是我发现unwind的回答更加清晰明了。 - static_rtti
3
“我没有要求使用的库”,这里说的是_boost_,而不仅仅是某个库。不管怎样,你的标准库实现很有可能自带std::tr1::array(C++03或TR1),甚至是std::array(C++1x),它们和boost提供的完全相同。(这表明boost不仅仅是另一个库。它是下一代C++标准的试验场,由std委员会成员创立,出于这个原因它具有非常高的质量标准和严格的审核流程,并为下一代标准库做出了大量贡献。) - sbi
3
在这里使用boost是完全不必要的,而且暗示使用库比使用标准语言特性更好,尤其是后者只需要更少的击键数,这种暗示是荒谬的。 - KomodoDave
1
@KomodoDave:嗯。你可能需要看一下我的评论日期。那时候还没有std::array。现在,我肯定会使用它。(然而,正如我所说,它是从boost中出来的。) - sbi

4

在C++中,您无法返回固定大小的数组。您可以返回指向int的指针(它将被用作数组),但这需要使用new在堆上分配数组。

不过,您可以将您的数组作为参数传递给函数:

void array_func( int result[3])
{
    result[0] = 1;
    result[1] = 1;
    result[2] = 1;
}

int main(int argc,char * argv[])
{
    int point[3];
    array_func( point );
}

然而,这看起来更像C而不是C++...

不一定需要使用“new”关键字。在array_func函数内部,也可以将数组声明为静态变量(当然这要取决于是否可行)。 - Christian
1
嗯,参数声明中的 3 不是被忽略了吗? - sbi
是的,你说得对,最后,我甚至不确定它是否能编译。你可能需要在函数声明中省略数组大小... - Adrien Plisson
1
@Adrien:它可以编译,但编译器将忽略数字3,静默地将结果类型从int result[3]“衰变”为int *result(通常甚至不会发出警告)。如果你问我,这有点狡猾的编译器 ;) - j_random_hacker
...并且也会打开缓冲区溢出的大门,但这就是C语言的工作方式。无论如何,当有意使用时,这个解决方案仍然有效。 - Adrien Plisson
将 array_func 的签名更改为“void array_func( int(&result)[3] )”可以防止您将大小不正确的数组传递给 array_func。 - user2796283

0

boost::array是一个基于栈的数组封装。

请注意,只有在不需要复制大型数组时,堆栈分配才比使用“new”更便宜。


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