tags:

views:

200

answers:

6

In my code, I want to use a byte-vector to store some data in memory. The problem is, that my current approach uses many lines of code:

std::vector<byte> v;
v.push_back(0x13);
v.push_back(0x37);
v.push_back(0xf0);
v.push_back(0x0d);

How can I shorten this procedure so that I have for example something like:

std::vector<byte> v(4) = "\x13\x37\xf0\x0d"; // example code - not working

?

+1  A: 
copy_n("\x13\x37\xf0\x0d",4,std::back_inserter(v));
Michael Krelin - hacker
As far as I can make out, copy_n is not part of the C++ Standard.
anon
Neil, it's easily converted to copy, but who cares about standard as long as it's available ;-) (I know, you do).
Michael Krelin - hacker
Well, you seem to care about the standard, as you (incorrectly) used the std:: namespace resolution. If you had said "use copy_n from library XXXX" I would have no objection.
anon
I do not see how my incorrect use of `std::` namespace shows my interest in standards, but other than that I finally got your point, you're perfectly right.
Michael Krelin - hacker
+6  A: 

The boost assignment library provides many useful helpers for this sort of thing. The first example in the docs is

#include <vector>
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
#include <boost/assert.hpp>; 
using namespace std;
using namespace boost::assign; // bring 'operator+=()' into scope

vector<int> v; 
v += 1,2,3,4,5,6,7,8,9;
timday
I've never been a big boost fan, though I do use some of their stuff in my projects. But this is a good example of why you should be very careful which bits of boost you use - not all of it is written by geniuses.
anon
What exactly do you have against boost assignment? I think it fixes a pretty common complaint about using standard containers instead of C style arrays (this exact issue). Unnecessary in C++1x, of course.
Terry Mahaffey
It's just a convenience feature, doing nothing you can't do via other nmechanisms. It's something I've never needed to do, and breaks my basic programming guideline regarding operator overloading - don't get too clever.
anon
I agree with Neil, operator overloading has been greatly abused in the past. At the end, the common advice has lead into 'do as basic types (int) do'. If addition is push_back, what is multiplication? (In python for strings it means actual multiplication: "a" * 4 == "aaaa"), but all those uses seem unnatural. Adding an int into a vector of ints could also be interpreted as adding the value to each element (If I recall correctly, that is the interpretation in matlab).
David Rodríguez - dribeas
I happen to like the syntax proposed by boost.assign, but i'd be curious to see what error message if i tried to add strings to v (in the provided example) : v += "a", "b", "c";
Benoît
As an alternative to v+=1,2,3... I believe boost assignment also lets you do push_back(v)=1,2,3... though of course the overloading of the comma-operator is probably considered even more unpalatable than += by those who object to such things; personally I've been doing a fair bit of Scala coding recently and am quite enjoying how it provides overloading capabilities beyond C++'s; c.f Java/C# which rejected C++-style overloading.
timday
+1  A: 

I have found one solution for my own now:

std::vector<byte> pattern(5);
memcpy(&pattern[0], "\xDE\xAD\xBE\xEF", 4);

Now the question transforms to: Which of the answers is the cleanest and "best" one?

Etan
Unsurprisingly, I vote for mine ;-) It doesn't pull in any huge dependencies and it works on stl container stl way. Yours *may* be a bit more performant, though.
Michael Krelin - hacker
std::copy actually has specializations for contiguous storage that distills down basically to a memcpy when compiled.
joshperry
joshperry: That's not guaranteed, though it's certainly possible to implement std::copy that way. The standard calls this a Quality of Implementation (QoI) issue. Of course the wise move is to use std::copy, find out if it's a performance bottleneck, and change things (including the possibility of changing stdlib implementation) then, if required.
Roger Pate
That's why I've used this italicized "may".
Michael Krelin - hacker
+4  A: 

Some newer compilers support brace initialization of vectors:

vector<byte> v = {0x13, 0x37, 0xf0, 0x0d};

If you compiler doesn't support that construct you can do what you were trying to do like this:

const byte initData[] = {0x13, 0x37, 0xf0, 0x0d};
std::vector<byte> v(initData, initData + sizeof(initData));

This just copies from const readonly memory into your live vector.

joshperry
"some new compilers" would require tag c++0x ;-)
Michael Krelin - hacker
As written here, you should use vector's ctor rather than copy, actually. And `sizeof(initData)/sizeof(char)` is just wrong: initData is a pointer, not an array; and if you're going to divide by the item size, use `sizeof array[0]` (or `sizeof *array`).
Roger Pate
This is wrong. The algorithm call is wrong, `initData` is defined as a pointer, so `sizeof(initData)` will be `sizeof(char*)` regardless of the number of elements. Even if it was an array, if you use a literal string for initialization it will have an extra `\0`. The irrelevant part is that you can use the iterator constructor: `char array[] = "\x13\37\xf0\x0d"; std::vector<char> v( array, array+(sizeof(array)/sizeof(array[0]) -1) );`
David Rodríguez - dribeas
+5  A: 

This solution gets the string length from the literal itself, meaning you don't need extra 5s and 4s lying around:

const unsigned char src[] = "\xDE\xAD\xBE\xEF";
std::vector<unsigned char> pattern(src, src+sizeof(src));

Note that a null terminator (extra zero byte) is added to the array; sizeof(src) is 5 because it's a string literal. The null terminator can be discarded by saying sizeof(src)-1, or by doing this:

const unsigned char src[] = {0xDE, 0xAD, 0xBE, 0xEF};
Joey Adams
+1, though you can change the order of declarations to simplify: `const unsigned char src[] = {0xDE, 0xAD, 0xBE, 0xEF}; vector<unsigned char> pattern (src, src + sizeof src);`.
Roger Pate
Incidentally, it's also easier to implement vector to discover it has been given random-access iterators (and that value\_type is POD, which is always true for built-in types like char) than it is to implement copy and discover 1) it has RA iterators, 2) of POD value\_type, and 3) the third parameter is a back\_inserter for a vector of the same value\_type. (This applies to it "compiling down" to a single memcpy, of course all of this is moot for a size of 4, anyway.)
Roger Pate
+2  A: 

As an alternative to boost assignment (see my other answer), simply define a helper

inline std::vector<byte>& operator<<(std::vector<byte>& v,byte x)
  {v.push_back(x);return v;}

then you can write

 std::vector<byte> v;
 v << 0x13 << 0x37 << 0xf0 << 0x0d;

Obviously you could template the helper on the container and/or contained type to make this more general (but then eventually you'd just be reimplementing boost assignment anyway).

timday