3

I want a standard C++ container to use as an accumulator for reading from a network socket (that is, T = byte or unsigned char). I want the container to reserve a capacity on construction, and not initialize the elements. That is, I want to be able to do:

container c(1024);

and get the container to reserve 1024 octets. One-step construction/capacity is important because I want to use it in an initializer.

I also want contiguous storage. If the containers must grow, the new storage should be contiguous.

I also want to be able to append bytes to the container. And I want to be able to search for byte strings in the container.

vector and string don't really fit because construction and reserve are two step process, they use an extra allocation, and they initialize elements. Plus, vector is missing the search functionality. (EDIT: vector is fine thanks to <algorithm>; thanks DYP and Lightness Races in Orbit).

Are there any C++ standard containers that have the properties?

jww
  • 97,681
  • 90
  • 411
  • 885
  • 6
    The closest is `std::vector`, but there is no container in the standard library that fits all your requirements. – Some programmer dude Jan 19 '14 at 13:53
  • "I want the container to reserve a capacity on construction, and not initialize the elements" -- Just does not make sense to me. All containers that will allocate memory will initialize it somehow. – Shoe Jan 19 '14 at 13:56
  • 1
    can you ever have more than 1024 octets for the container? if not use [std::array](http://www.cplusplus.com/reference/array/array/) – Gasim Jan 19 '14 at 13:56
  • @Jefffrey, no, for chars – qwm Jan 19 '14 at 13:57
  • i mean will it initialize elements on only within 1024 octets? Can it ever be a little more – Gasim Jan 19 '14 at 13:57
  • @Gasim - yes, the accumulator might grow if I can't service a request fast enough. – jww Jan 19 '14 at 13:58
  • then your best bet is using `std::vector`, the vector has a [reserve](http://www.cplusplus.com/reference/vector/vector/reserve/) function, which reserves the area but doesn't initialize it – Gasim Jan 19 '14 at 14:00
  • Could this be where `std::dynarray` comes in? :P **edit:** Nevermind. ;~; – user123 Jan 19 '14 at 14:01
  • `After reviewing national body comments to n3690, this library component was voted out from C++14 working paper into a separate Technical Specification. This container is not a part of the draft C++14 as of n3797` – Gasim Jan 19 '14 at 14:02
  • 3
    @Gasim but this `vector` will still think its `size() == 0` – qwm Jan 19 '14 at 14:02
  • 1
    Anyway, it feels odd to use high-level constructs in low-level code – qwm Jan 19 '14 at 14:05
  • but the `capacity() == 1024`; and yes forcing STL on a low level code is pointless. – Gasim Jan 19 '14 at 14:06
  • 6
    You can use an allocator that doesn't value-initialize (or doesn't initialize at all) the newly constructed elements. See http://stackoverflow.com/a/21028742/420683 – dyp Jan 19 '14 at 14:06
  • @qwm - I want the buffer management without some of the STL overhead. I'm probably being too greedy. – jww Jan 19 '14 at 14:07
  • @dyp - was it https://stackoverflow.com/questions/2676988/how-to-change-size-of-stl-container-in-c? Specifically potatoeswatter's answer? – jww Jan 19 '14 at 14:08
  • @noloader No, that's not the one I meant (I updated my comment with the link I've been referring to) Potatoswatter's answer also doesn't work for class types that have a user-defined default constructor. – dyp Jan 19 '14 at 14:10
  • 4
    `vector and string don't really fit because construction and reserve are two step process` You're asking the wrong question. Instead of "all these containers are wrong; please find me a container to do all these magical things", it's "vector or string is perfect; now how do I roll reservation into construction? do I need a wrapper?" – Lightness Races in Orbit Jan 19 '14 at 14:11
  • @LightnessRacesinOrbit - yeah, I almost asked a second question like that (it was closer to dwp's suggestion). But I thought I might be wandering too far off track for this question. Or worse, wandering into the opinion-based close. – jww Jan 19 '14 at 14:14
  • 1
    *"Plus, vector is missing the search functionality."* Just because it doesn't have such a member function doesn't mean that you cannot search it. Most parts of the Standard Library have minimal interfaces. `std::string` is a very unfortunate exception IMO. Use free functions e.g. from `` instead. – dyp Jan 19 '14 at 14:14
  • @dyp - yeah, good point. I forgot about ``. I'm sure I would have turned to it once I started coding. – jww Jan 19 '14 at 14:15

1 Answers1

4

You are asking the wrong question.

The Standard Library does not provide a container for each and every use, instead it provides a selection of useful building bricks.

If you want contiguous storage, then you should be using std::vector and look into making it match your other requirements:

  • non-initialization is accomplished by providing an allocator with a no-op construct method
  • and searching for a pattern is accomplished by using std::search or rolling your own specific search algorithm (Knuth Morris Pratt, Boyer Moore, ...)

In any case, I advise encapsulating the vector into a dedicated class with a clear semantic role.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • Thanks Matthieu M. So I'm clear: suppose I encapsulate a vector. When I initialize my wrapper object during construction, I'm going to try and initialize the underlying vector. Which appears to bring me right back to the original problem of reservation without element initialization during construction of a standard container. – jww Jan 19 '14 at 14:36
  • @noloader: no, as I mentioned, just use a `vector` with an allocator parameter of your own which has a no-op `construct`; then the call to `resize` will not initialize the storage reserved. (Though I do not understand why you so focus on obtaining uninitialized storage, there is little point in such a quest here) – Matthieu M. Jan 19 '14 at 15:27
  • Thanks Matthieu M. - that's `reserve`, not `resize`. The idea to to preallocate a buffer of optimal size ('optimal' will be determined during runtime evaluation). The reason for avoiding initializing the elements is purely optimization - I don't need it, so I want to forgo it to allow the routine to run faster. – jww Jan 19 '14 at 15:31
  • 1
    @noloader `resize` uses the `vector`'s allocator to allocate *and* value-initialize (in a second step) the newly allocated elements. If you design your allocator *to do a no-op for value-init*, your `resize` will only allocate. With optimizations, the compiler could remove the loop of no-ops that is intended to initialize the new elements inside `resize`. – dyp Jan 19 '14 at 15:35
  • 2
    @noloader: dyp already answered your point; so let me comment on the optimization. *Is it worth it ?* I say **no**, in all likelihood. It is commendable to wish for a fast function/program, however you need to focus on performance bottlenecks first and foremost. Given that we are talking about a small piece of memory (1/4 of a typical OS page), the cost of initializing it is probably dwarfed by the network read; and of course the search algorithm is probably even more costly as well... So, write a **correct** program first, with a test suite, and then profile to optimize. – Matthieu M. Jan 19 '14 at 15:58