In article <1160343872.640503.196840@k70g2000cwa.googlegroups .com>,
lancediduck@nyc.rr.com wrote:
Quote:
Pete C wrote:
Quote:
lancediduck@nyc.rr.com wrote:
Quote:
Szabolcs Horvát wrote:
>
int main() {
map<int, Am;
A a;
m[0] = a;
return 0;
}
This behavior is implementation dependent, and not all compiler setting
or library implementation will give you the same results.
The Standard (23.3.1.2) says that map::operator[] :
Returns: (*((insert(make_pair(x, T()))).first)).second
I'm not sure how to interpret this: does it mandate the implementation,
or does it just specify that the return value should be "equivalent to"
that expression?
Your explanation is correct of course but I suspect that this
inefficiency is required by the standard.
>
That it is equivalent to that expression. I dont know why the standard
is so terse - it almost looks more like LISP than C++ with all those
parens. The expanded version is easier to read, and no less difficult
for a complier to optimize.
The reason that results may differ, is that for one you could get MORE
copies in a conforming implementation. Or, perhaps that the tree used
needed to rebabalance on the insertion (most implementors choose to
implement map as an rbtree) and you would see different results. Also,
in some implementations, implementors play with move constructors --
they know that for some types they are going to make a copy and then
destroy it or otherwise overwrite it, so in a few cases, you can save a
copy.
Fwiw, I don't currently see a conforming way to reduce the number of
copies below two:
You need a copy of the default constructed element in order to form the
pair<key,value>. There's no way to construct a pair with just a copy of
the key, and default construct the value in place. And then that pair
must be copy constructed because that is the only interface available to
allocator::construct (which needs to construct from a copy), which the
map is supposed to use.
If move semantics comes to pass in C++0X, then for expensive A's, the
following will (usually) help:
class A {
int whoami;
public:
A() {
whoami = counting_As++;
cout << "constructor " << whoami << endl;
}
~A() {
cout << "destructor " << whoami << endl;
}
A(const A &p) {
whoami = counting_As++;
cout << "copy cons " << whoami << " from " << p.whoami << endl;
}
A(A &&p) {
whoami = counting_As++;
cout << "move cons " << whoami << " from " << p.whoami << endl;
}
A & operator = (const A &p) {
cout << "assignment " << whoami << " from " << p.whoami << endl;
return (*this);
}
};
constructor 0
constructor 1
move cons 2 from 1
move cons 3 from 2
destructor 2
destructor 1
assignment 3 from 0
destructor 0
destructor 3
The move constructor is allowed to transfer resources from the source
object to construct itself (like auto_ptr "copy").
-Howard