So on further study, I learned two things:
boost::multi_array
uses the copy constructor to initialize objects into the container, not the default constructor.
The for (auto x : container)
way of looping in C++11 seems (at least with clang++ 3.5) to loop over copies of the container elements, rather than iterators (or references).
Modifying the original question's example to demonstrate point 1.
Adding a copy constructor (and corresponding counter), and using auto& x
for the object loops rather than auto x
:
static int num = 0;
static int cpy = 0;
struct A {
int n;
int c;
A() : n((::num)++), c(0) {
std::cout << "A_def()" << std::endl;
}
A(const A& o) : n(0), c((::cpy)++) {
std::cout << "A_cpy()" << std::endl;
}
virtual ~A() {}
void print() {
std::cout << "n=" << n << ",c=" << c << std::endl;
}
};
int main() {
std::cout << "vector:" << std::endl;
std::vector<A> v(3);
for (auto& x : v) {
x.print();
}
std::cout << "multi:" << std::endl;
boost::multi_array<A, 2> m(boost::extents[2][2]);
for (auto x : m) {
for (auto& y : x) {
y.print();
}
}
}
Produces the output
vector:
A_def() // <- vector allocation starts
A_def()
A_def()
n=0,c=0 // <- vector printing starts, using "for (auto& x)"
n=1,c=0
n=2,c=0
multi:
A_def() // <- a temporary object for multi_array allocation
A_cpy() // <- multi_array allocation starts
A_cpy()
A_cpy()
A_cpy()
n=0,c=0 // <- multi_array prints starts, using "for (auto& y)"
n=0,c=1
n=0,c=2
n=0,c=3
Modifying the example above to demonstrate point 2.
Same class definition as above in this answer, but removing the auto& x
from the object loops, and going back to using auto x
as done in the original question.
std::cout << "vector:" << std::endl;
std::vector<A> v(3);
for (auto x : v) {
x.print();
}
std::cout << "multi:" << std::endl;
boost::multi_array<A, 2> m(boost::extents[2][2]);
for (auto x : m) {
for (auto y : x) {
y.print();
}
}
Produces output that shows the copy constructor gets called during the print
loops, even for elements in the vector
.
vector:
A_def() // <- vector allocation starts
A_def()
A_def()
A_cpy() // <- vector printing starts, using "for (auto x)"
n=0,c=0
A_cpy()
n=0,c=1
A_cpy()
n=0,c=2
multi:
A_def() // <- a temporary object for multi_array allocation
A_cpy() // <- multi_array allocation starts
A_cpy()
A_cpy()
A_cpy()
A_cpy() // <- multi_array printing starts, using "for (auto y)"
n=0,c=7
A_cpy()
n=0,c=8
A_cpy()
n=0,c=9
A_cpy()
n=0,c=10