3

In my attempt to create a custom string class without dynamic memory, I'm using the template array length trick. Because the size is passed as a template parameter, it is known at compile time. So therefore char buffer[n] is not a variable length array. Is this correct line of thinking? Here's code:

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);
}

Hopefully by this method all memory is on stack and I don't run into any issues with new, delete and so on.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • 7
    Correct. `buffer` is not a VLA. – juanchopanza Sep 16 '14 at 21:51
  • 1
    You probably could have done this: `basic_string, YourAllocator>` where the allocator is stack based. Then you get everything else for free instead of rewriting all the code. http://en.cppreference.com/w/cpp/string/basic_string – PaulMcKenzie Sep 16 '14 at 21:55
  • Yes, there's `std::vector<>` to have _variable length arrays_. – πάντα ῥεῖ Sep 16 '14 at 21:56
  • 2
    Just be very careful with `string_test` -- it will attempt to allocate several gigabytes :-) Also, your `strcopy` is not safe since that copies the null byte too, which you don't have room for (and is not safe in general since the passed in string could be longer than `n`). – Cameron Sep 16 '14 at 21:58
  • @PaulMcKenzie: I keep wishing there was some mechanism for the allocator to tell vector/string to preallocate a certain amount during construction. – Mooing Duck Sep 16 '14 at 22:15
  • @Cameron Why is that? And to OP: `n` is a template variable and determined at compile time. So no it is not variable length array – SwiftMango Sep 16 '14 at 22:15
  • 1
    @texasbruce: n is `size_t`, which is unsigned. The OP is subtracting one from it. If you subtract one from an unsigned 0, it wraps around to the *largest* value that the type can hold (all 1 bits). Boom! :-) – Cameron Sep 17 '14 at 01:04
  • +1 Related to [Does “int size = 10;” yield a constant expression?](http://stackoverflow.com/q/21273829/1708801) ... as I explain in my answer if the array bound is a constant expression then it is not a VLA. – Shafik Yaghmour Sep 17 '14 at 01:34
  • Also, if you are using `gcc` or `clang` then the `-pedantic` flag will warn you when you are using an extension, which would apply in the case of VLAs since they are not part of C++ and so would only work as an extension. Visual Studio as far as I know still does not support VLA as an extension in C++. – Shafik Yaghmour Sep 17 '14 at 01:44
  • C++ does not have VLAs, therefore it is not a VLA. – M.M Sep 17 '14 at 02:21
  • `size_t _size = n - 1;` is unnecessary. Change `size` function to `constexpr size_t size() { return n - 1; }` – M.M Sep 17 '14 at 02:23
  • @MattMcNabb if you are using `gcc` or `clang` they will happily let you use VLAs as an extension without warning unless you use the right flags. – Shafik Yaghmour Sep 17 '14 at 02:34

2 Answers2

3

Yes, your thinking is correct: buffer is not a VLA.

Hopefully by this method all memory is on stack and I don't run into any issues with new, delete and so on.

This is also correct in the sense that you don't need to manage any memory by hand.

One (potentially significant) wrinkle is that string_test<T, m> and string_test<T, n> are different types when m != n.

In general it would seem more appropriate to simply use std::vector<T>. This will lead to straightforward yet correct code with little scope for memory errors.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • @chris: Thanks, will fix the wording in a moment (I am a bit out of date on this). – NPE Sep 16 '14 at 22:09
  • +1 See my [comment](http://stackoverflow.com/questions/25879007/is-this-a-variable-length-array-or-no#comment40503253_258790070) above for a related question. Since `n` is a constant expression it is not a VLA. – Shafik Yaghmour Sep 17 '14 at 01:36
0

The code and the thinking is not wrong; and will work as is.

I would question the motive and the means to achieve it. The class is not safe in terms of bounds checking. For instance, if ctor is given a string exceeding the capacity, BANG.

Heap memory management is as efficient as it can be, and I do not foresee performance problems for 99.99% applications. If you REALLY are trying to squeeze the last CPU performance drops, perhaps using STL is not the right choice. You should limit yourself to classic C-style programming with hand-crafted optimized algorithms.

Last, I second PaulMcKenzie above that, if you want to customize memory management for any of the containers (string included), use std class with custom allocator. You can construct an allocator with automatic buffer on the stack and make it use that buffer.

ArunasR
  • 1,907
  • 1
  • 14
  • 15