Array inside struct inside container

N

none

I've seen forum posts here and there asking "How do I create an STL
container of arrays?" Or, equivalently, "How do I fix this syntax:"

std::vector<float[20]> v;

The answers to these questions are generally one of two things:

1) Use a boost::array, or
2) Put the array in a struct, like so:

// In header file
stuct wrapper { float f[20]; };

// In CPP file
std::vector<wrapper> v;

I was under the impression that things stored in STL containers needed to
be copyable and assignable. That second option seems incorrect to me,
unless the compiler is expected to generate both an operator= and a copy
constructor for the struct that perform a memcpy() for the contents of f.

Is it?
 
V

Victor Bazarov

I've seen forum posts here and there asking "How do I create an STL
container of arrays?" Or, equivalently, "How do I fix this syntax:"

std::vector<float[20]> v;

The answers to these questions are generally one of two things:

1) Use a boost::array, or
2) Put the array in a struct, like so:

// In header file
stuct wrapper { float f[20]; };

// In CPP file
std::vector<wrapper> v;

I was under the impression that things stored in STL containers needed to
be copyable and assignable. That second option seems incorrect to me,
unless the compiler is expected to generate both an operator= and a copy
constructor for the struct that perform a memcpy() for the contents of f.

Not memcpy. See below.

A struct with an array as a data member is assignable. The default
compiler-provided assignment operator performs memberwise assignment
that for array members means element-wise assignment. You can verify it
by compiling/running this test program:

#include <iostream>

struct A {
A& operator=(A const&) { std::cout << "A::eek:p=\n"; return *this; }
};
struct B { A aa[10]; };

int main() {
B b1, b2;
b1 = b2;
}

V
 
N

none

Victor said:
A struct with an array as a data member is assignable. The default
compiler-provided assignment operator performs memberwise assignment
that for array members means element-wise assignment.


Thanks! I was uninformed. I've been using wrapper classes in my
ignorance, which do perform a memcpy(). This means that I could get rid of
them, but based on your example, I think the memcpy() might be slightly
faster. It's a micro-optimization, I know, but it looks like the compiler
inserts something like a for-loop that invokes operator= for each element,
where memcpy() is probably optimized down to basically a single REP-MOV
instruction on x86. Or, maybe I'm just emotionally attached to my wrapper
classes now and want to continue using them.
 
A

Alain Ketterlin

none said:
Thanks! I was uninformed. I've been using wrapper classes in my
ignorance, which do perform a memcpy(). This means that I could get rid of
them, but based on your example, I think the memcpy() might be slightly
faster. It's a micro-optimization, I know, but it looks like the compiler
inserts something like a for-loop that invokes operator= for each element,
where memcpy() is probably optimized down to basically a single REP-MOV
instruction on x86.

You should better leave that optim to the compiler (it probably does it
already for pod types). And your code will also "do the right thing"
when operator= on array elements does non-trivial things, i.e., on
non-pod types.

-- Alain.
 
B

Bo Persson

none said:
Thanks! I was uninformed. I've been using wrapper classes in my
ignorance, which do perform a memcpy(). This means that I could
get rid of them, but based on your example, I think the memcpy()
might be slightly faster. It's a micro-optimization, I know, but
it looks like the compiler inserts something like a for-loop that
invokes operator= for each element, where memcpy() is probably
optimized down to basically a single REP-MOV instruction on x86.
Or, maybe I'm just emotionally attached to my wrapper classes now
and want to continue using them.

The compiler can easily optimize the memberwise copy into a memcpy()
whenever that is possible (and deemed "slighly faster").

It is an old myth that memcpy() is always the fastest. Smart compilers
can do a lot of things that is sometimes ever better (like taking
advantage of known alignment and size).



Bo Persson
 
J

Juha Nieminen

Bo Persson said:
The compiler can easily optimize the memberwise copy into a memcpy()
whenever that is possible (and deemed "slighly faster").

It is an old myth that memcpy() is always the fastest. Smart compilers
can do a lot of things that is sometimes ever better (like taking
advantage of known alignment and size).

Another important aspect is that if the elements happen to be class
instances, memcpy() could potentially break it badly. It's just better
to let the compiler do the copying unless there's a good reason not to.
 
N

none

I've seen forum posts here and there asking "How do I create an STL
container of arrays?" Or, equivalently, "How do I fix this syntax:"

std::vector<float[20]> v;

The obvious answer is:

std::vector said:
The answers to these questions are generally one of two things:

1) Use a boost::array, or
2) Put the array in a struct, like so:

// In header file
stuct wrapper { float f[20]; };

// In CPP file
std::vector<wrapper> v;

I was under the impression that things stored in STL containers needed to
be copyable and assignable. That second option seems incorrect to me,
unless the compiler is expected to generate both an operator= and a copy
constructor for the struct that perform a memcpy() for the contents of f.

Is it?
 
J

James Kanze

On 16/08/2011 21:07, none wrote:
Your opimization is indeed premature: VC++, for example, will emit a REP
MOVS instruction when copying member arrays of builtin types.

Even today? I seem to recall reading somewhere (of unknown
reliability, so it could easily be wrong) that on a modern
machine, REP MOVS was less efficient than a loop using more
classical instructions.

Anyway, as Bo has pointed out, the compiler can take advantage
of known alignment, etc., and can certainly generate faster code
than would result from calling memcpy.
 
N

none

I've seen forum posts here and there asking "How do I create an STL
container of arrays?" Or, equivalently, "How do I fix this syntax:"

std::vector<float[20]> v;

The obvious answer is:

std::vector< std::vector<float> > v;

Not always ideal as the array elements will not be contiguous (might be
a requirement) and the overhead of the separate allocation for each
array "row" might be undesirable.

Yes, by all mean, there *might* be special cases where
std::vector< std::vector<float> > v;
is not the ideal answer. However, it certainly should be one of the first
thing you consider.

The OP did not request contiguous memory nor particular performance
requirements. You should only use a more complex and potentially more
error prone construct if and only if profiling and analysis shows that
such a potentially more error prone construct is needed.

Yan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top