6

我们都知道静态数组的基本规则:

int size = 20;
char myArray[size];

是不合法的。和。

const int size = 20;
char myArray[size];

没关系。

但是,这又如何。

int f(const int size)
{
    char myArr[size];
}

void main()
{
   f(2);
   f(1024);
}

MSVC 说这是一个错误,gcc 似乎可以编译并执行它。

显然,它不可移植,但它应该被接受吗?

哪个编译器在这种情况下做正确的事情?

此外,如果编译器允许,那么良好的编程标准/实践是否应该允许?

编辑:这个想法是我想要堆栈分配速度,但我在编译时不知道数组的大小。我知道还有其他一些解决方案,堆栈分配可能不会是一个有意义的优化,但我认为这是一个有趣的用法。

4

5 回答 5

9

不,C++ 没有变长数组。C99 可以,gcc 通过扩展允许它。

使用std::vector.


假设您已经分析了您的应用程序并发现这是一个瓶颈,请编写一个从堆栈分配的自定义分配器并使用它。如果没有,则没有问题。

堆栈分配非常快,但这可能不会成为实际应用程序中的主要问题。(您应该有一个自定义的内存管理方案,其性能将接近堆栈分配的速度。)

于 2010-10-22T14:21:18.903 回答
3

您可以为此使用 std::array 。std::array 已添加到 TR1 扩展中,可在命名空间 std 或 std::tr1 中使用,具体取决于您使用的编译器/标准库版本。

#incldue <array>
int main()
{
   std::tr1::array<int,25> myArray;
   //etc...
   myArray[2] = 42;
}

重新阅读有关堆栈分配的问题...

如果你想要堆栈分配,你可以使用 alloca 在堆栈上分配而不是 malloc(所有通常的警告都适用)。

如果你想要一个更友好的界面,你可以实现一个基于 alloca 的自定义 stl 分配器,并使用 std::vector (你应该在实现之前阅读)。

例如:

#include <vector>
template <class T>
class MyStackAllocator
{ // implemented per std::allocator spec
...
}
int main()
{
//allocate a vector on the stack and reserve n items
vector<int, MyStackAllocator<T>> vecOnStack(25);
...
}
于 2010-10-22T14:38:15.733 回答
1

此线程中实际上提供了正确答案,因此我只想为其提供更多上下文。

您需要创建使用alloca()(或_alloca()在 Windows 中)函数进行动态堆栈分配的自定义分配器。创建一个非常容易,您可以使用典型的分配器样板,将 allocate() 成员函数更改为return (pointer)(alloca(size * sizeof(T)));并使deallocate()函数为空,因为没有手动堆栈释放。之后,您可以将分配器提供给标准容器,例如vector<T, stack_allocator<T>>.

不过,有两个警告。可分配的堆栈大小可能会有很大差异,通常您可以选择在编译时设置它。我相信 32 位应用程序中的 Visual Studio 默认将其限制为 1MB。其他编译器可能有不同的限制。在 64 位应用程序中,实际上没有任何问题,因为堆栈可以和堆一样大。您可能需要在堆栈溢出时捕获结构化异常并将其转换为 C++ 异常。

第二个警告,你不应该在你的函数之外复制堆栈指针,所以移动语义,例如,如果你将堆栈分配的对象传递给函数/从函数传递,那么移动语义将不起作用。

还有一个不便之处,您不能复制具有不兼容分配器的容器,但您可以逐个元素地复制它们。例如

vector<int> vint;
vector<int, static_allocator<int>> vsint;

vint = vsint; // won't compile, different allocators
std::copy(vsint.begin(), vsint.end(), vint.begin()); // fine
于 2010-10-29T17:35:35.437 回答
1

C99 支持可变长度数组 (VLA),但 C++ 不支持。gcc 允许它通过扩展。

std::vector 在 C++ 中所做的与 VLA 在 C99 中所做的相同

于 2010-10-22T14:54:24.790 回答
0

你真正想要的并不完全是你所要求的。似乎您真的想要一个数字到数字的映射,例如索引 2042 的值是 23,等等。

由于您实际上并不知道您可能想要使用的最高数字的上限,因此您可能必须以使用(数学)映射的方式重组您的代码,而不是考虑 2042 的索引数组持有,您认为 2042 是访问值 23 的键。

----回答我们可以分配一个具有以下执行时间常数的静态数组---

init()如果您想要一个执行时静态数组,最好的选择是使用替代指针语法声明数组,然后在程序执行开始时将其初始化为非静态函数。

如果您尝试在执行之前分配数组,main(...)则会冒着不知道将按什么顺序调用哪些静态代码块的风险。有时这没什么区别;但是,在您的情况下,您似乎需要在运行时计算数字,因此模块的顺序变得很重要。

通过使用非静态方法,您基本上可以保证在分配数组之前执行所有静态代码。

于 2010-10-22T14:23:05.213 回答