这是一个变长数组吗?

3

我试图创建一个不使用动态内存的自定义字符串类,我正在使用模板数组长度技巧。因为大小作为模板参数传递,所以在编译时就已知。因此,char buffer[n] 不是变长数组。这样想对吗?以下是代码:

template<typename T, size_t n>
class string_test
{
    using Type = T;
    // Don't count NUL byte
    size_t _size = n - 1;
    char buffer[n]; // <--- variable length array?
public:
    string_test(const char* str)
    {
        strcpy(buffer, str);
    }

    size_t size() const
    {
        return _size;
    }

    const char* c_str() const
    {
        return buffer;
    }
};

template<typename T, size_t n>
string_test<T, n> make_string(const T (&str)[n])
{
    return string_test<T, n>(str);
}

希望通过这种方法所有的内存都在栈上,我不会遇到任何关于new、delete等方面的问题。


7
正确。buffer 不是可变长度数组(VLA)。 - juanchopanza
1
你可能可以这样做:basic_string<char,char_traits<char>,YourAllocator>,其中分配器是基于堆栈的。然后你就可以获得其他所有东西,而不必重写所有代码。http://en.cppreference.com/w/cpp/string/basic_string - PaulMcKenzie
2
请非常小心string_test<char, 0> - 它将尝试分配数千兆字节 :-) 此外,您的strcopy不安全,因为它也会复制空字节,而您没有足够的空间来存储它(在一般情况下也不安全,因为传入的字符串可能比n更长)。 - Cameron
@PaulMcKenzie:我一直希望有一种机制,让分配器在构造期间告诉vector/string预先分配一定数量的空间。 - Mooing Duck
1
@texasbruce:n是size_t,也就是无符号类型。OP正在从中减去1。如果你从一个无符号的0中减去1,它会绕回到该类型可以容纳的最大值(所有1位)。炸了! :-) - Cameron
显示剩余7条评论
2个回答

3

是的,你的想法是正确的:buffer 不是 VLA。

希望通过这种方法所有内存都在堆栈上,我不会遇到任何与 new、delete 等相关的问题。

这也是正确的,因为您无需手动管理任何内存。

一个(可能相当重要的)问题是,当 m != n 时,string_test<T, m>string_test<T, n> 是不同的类型。

一般来说,似乎更合适的是简单地使用 std::vector<T>。这将导致直接而正确的代码,并且很少有内存错误的机会。


@chris:谢谢,我马上会修正措辞(我对此有点过时了)。 - NPE
请参考我在此处的评论,了解相关问题。由于n是一个常量表达式,因此它不是VLA。 - Shafik Yaghmour

0

代码和思路并没有错,可以直接使用。

我会质疑实现这个目的的动机和手段。这个类在边界检查方面不安全。例如,如果ctor给出一个超过容量的字符串,就会崩溃。

堆内存管理已经尽可能高效,我不认为99.99%的应用程序会有性能问题。如果你真的想要挤出最后一点CPU性能,也许使用STL不是正确的选择。你应该限制自己使用手工优化算法的经典C风格编程。

最后,我赞同上面的PaulMcKenzie的观点,如果你想为任何容器(包括字符串)定制内存管理,请使用带有自定义分配器的std类。你可以构造一个自动缓冲区的分配器,并让它使用该缓冲区。


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