|
Boost : |
From: Rob Stewart (stewart_at_[hidden])
Date: 2005-08-19 08:08:59
From: Christopher Kohlhoff <chris_at_[hidden]>
> >
> The performance problems of requiring vector<char> or char[N] exist on
> several levels:
>
> - For vector<char>, there is the initialisation of the chars to 0 on
> construction or when you do a resize. Note that this is proportional to
> the size of the vector, not necessarily to the amount of data
> transferred. I have seen this have a noticable cost in a CPU-bound
> server handling thousands of connections.
Don't construct a vector of a given size or use resize(), then.
Rely on reserve() instead.
> - Requiring a copy from a native data structure into vector<char> or
> char[N]. If I have an array of a doubles say, I should be able to send
> it as-is to a peer that has identical architecture and compiler.
> Avoiding unnecessary data copying is a vital part of implementing high
> performance protocols.
Agreed. OTOH, using swap(), *if* a user used a vector<double>
instead of the array you mention, then vector won't add overhead.
> I believe that adding safety is best done in layers, in
> accordance with the don't pay for what you don't need principle:
>
> asio::socket::send/recv etc taking void* + size_t. These functions can
> result in a short send or receive.
> ^
> |
> asio::send_n/recv_n etc taking void* + size_t. These functions attempt
> to transfer the all of the requested data.
> ^
> |
> asio::send_?/recv_? etc. New functions that take safe types like
> vector<char> and char[N].
std::vector takes an allocator template and constructor
argument. A suitable allocator type could be constructed to
"allocate" from a user-supplied buffer and fail when that buffer
is exhausted. The problem here is that the Standard allows all
instances of the same type to be considered equivalent, so this
won't work.
Instead, how about a std::vector-like class that takes a
user-defined, fixed-size block of memory? Then, instead of using
an allocator, it uses its own memory management class that doles
out elements from the fixed, user-supplied memory. Such a class
could even avoid the default construction worry altogether by
eliminating resize() and making the constructor that takes a
number simply reserve that much space. (Deviating that much from
std::vector means you wouldn't want to make it too similar, or at
least you'd want the name to be quite dissimilar.) Using a
user-supplied block of memory means that the memory can come from
a stack allocation, static memory, the free store, a memory
mapped file, etc. That class cannot be copyable, but it could be
movable and swappable.
The advantage is that all of the asio functions can be written in
terms of that, getting buffer overrun protection for free, and
there's no (or extremely little) added overhead.
-- Rob Stewart stewart_at_[hidden] Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk