Consider the following:
// Contrast different ways of inserting into a map
#include <map>
#include <iostream>
using namespace std;
struct A
{
A () {cout << "ctor\n";}
A (const A& a) {cout << "copy ctor\n";}
A& operator= (const A& a) {cout << "op=\n"; return *this;}
};
typedef map<int,A> IAMap;
typedef IAMap::value_type IAMVal;
int main()
{
cout << "\nm1[0] = ...\n";
IAMap m1;
m1[0] = A();
cout << "\nm2.insert(IAMVal...)\n";
IAMap m2;
m2.insert(IAMVal(0,A()));
}
// end of code
The output is:
m1[0] = ...
ctor
copy ctor
copy ctor
ctor
op=
m2.insert(IAMVal...)
ctor
copy ctor
copy ctor
// end of output
First of all, are the two copy ctor calls both necessary? I gather that
one occurs when constructing the temporary IAMVal and a second occurs
when copying that temporary into the map. Can a smart compiler
eliminate (elide?) the construction of the temporary? (My version of
gcc with maximum optimiztion will not do so.)
On a related note, in Scott Meyers's "Effective STL" he compares these
two approaches in the contexts of inserts (new key) vs. updates
(existing key with new data). He states about inserts, "Efficiency
considerations thus lead us to conclude that insert is preferable to
operator[] when adding an element to a map..." And so it would appear
by simply counting the number of operations above.
But now suppose my data type contains a vector which is empty for a
default constructed object and I want to insert an object whose vector
isn't empty. Comparing the two approaches and paying attention only to
operations which involve the nonempty vector (since this is ostensibly
more work), the insert approach involves two copies of the nonempty
vector while the [] appraoch involves only one assignment of the
nonempty vector. (Unless of course the compiler can eliminate one of
the copies.) Am I looking at this right?
Thanks,
Mark 4 2444
"Mark P" <us****@fall2005REMOVE.fastmailCAPS.fm> wrote in message
news:fj******************@newssvr29.news.prodigy.n et... Consider the following:
// Contrast different ways of inserting into a map
#include <map> #include <iostream>
using namespace std;
struct A { A () {cout << "ctor\n";} A (const A& a) {cout << "copy ctor\n";} A& operator= (const A& a) {cout << "op=\n"; return *this;} };
typedef map<int,A> IAMap; typedef IAMap::value_type IAMVal;
int main() { cout << "\nm1[0] = ...\n"; IAMap m1; m1[0] = A();
cout << "\nm2.insert(IAMVal...)\n"; IAMap m2; m2.insert(IAMVal(0,A())); }
// end of code
The output is:
m1[0] = ... ctor copy ctor copy ctor ctor op=
m2.insert(IAMVal...) ctor copy ctor copy ctor
// end of output
First of all, are the two copy ctor calls both necessary? I gather that one occurs when constructing the temporary IAMVal and a second occurs when copying that temporary into the map. Can a smart compiler eliminate (elide?) the construction of the temporary? (My version of gcc with maximum optimiztion will not do so.)
On a related note, in Scott Meyers's "Effective STL" he compares these two approaches in the contexts of inserts (new key) vs. updates (existing key with new data). He states about inserts, "Efficiency considerations thus lead us to conclude that insert is preferable to operator[] when adding an element to a map..." And so it would appear by simply counting the number of operations above.
But now suppose my data type contains a vector which is empty for a default constructed object and I want to insert an object whose vector isn't empty. Comparing the two approaches and paying attention only to operations which involve the nonempty vector (since this is ostensibly more work), the insert approach involves two copies of the nonempty vector while the [] appraoch involves only one assignment of the nonempty vector. (Unless of course the compiler can eliminate one of the copies.) Am I looking at this right?
I'm no expert with this stuff, but:
Yes, I believe the compiler is allowed to elide a copy
ctor call as long as the resulting behavior is the same
('efficiency' not being part of 'behavior'). However,
since your copy ctor includes code for output, it must
be called, since its behavior differs from a default
copy ctor. Rather than your 'high level' analysis using
outputs, try taking them out and watching with a debugger.
If your compiler does elide the calls, stepping through
the code should reflect that.
I don't know if there are circumstances where a compiler
could elide a call to operator=() though.
HTH,
-Mike
Mark P wrote:
[ ... ] m1[0] = A();
[ ... ]
m2.insert(IAMVal(0,A()));
[ ... ]
First of all, are the two copy ctor calls both necessary?
No. According to the standard ($12.8/15), when a temporary class object
is copied using a copy ctor, and the object and the copy have the same
cv-qualification, the compiler is allowed to elide the copy ctor, even
if the copy ctor (and/or dtor) has side effects.
[ ... ]
On a related note, in Scott Meyers's "Effective STL" he compares these two approaches in the contexts of inserts (new key) vs. updates (existing key with new data). He states about inserts, "Efficiency considerations thus lead us to conclude that insert is preferable to operator[] when adding an element to a map..." And so it would appear by simply counting the number of operations above.
When you use operator[], it has to return a reference to some object,
so it has to have an object to return a reference to -- which means
default constructing an object. Once you've created that default
object, you immediately replace it with a copy of the other object
being inserted. Even a compiler that can sometimes elide the use of the
copy ctor might easily have difficulty doing so in this situation.
--
Later,
Jerry.
What you say about insert vs. operator[] is correct, but I think the
potentially surprising thing here is that even operator[] on its own
(without the assignment) yields two calls to the copy constructors.
That is to say,
m1[0];
produces:
ctor
copy ctor
copy ctor
This is because libstdc++'s implementation of operator[] does the
following:
1) Constructs a temporary A object (ctor call)
2) Uses the temporary A to construct temporary IAMVal (copy ctor)
3) Calls insert with the temporary IAMVal (copy ctor when insertion
occurs)
This seems inefficient but the implementation is specified by the
standard (23.3.1.2).
What's worse is that the compiler can't elide either of the copy
constructors, because in both cases the temporaries have been bound to
const references at the point the copy construction occurs. Consider
the difference between these two functions:
void f(const A &a) {
// even if 'a' refers to a temporary, eliding impossible
// here. copy ctor used
A b = a;
}
void f() {
A b = A(); // eliding possible, so ctor called just once
}
...
f((A())); // temporary bound to const ref. - calls ctor and copy ctor
f(); // only default ctor is called
So the problem is with the STL, not the compiler. It would be nice to
have a map::operator[] that just called the default constructor in the
case that the entry needed to be created, but the standard doesn't
permit it.
Have I got that right?
I think you are looking at it right, but I doubt you'll get the
compiler to eliminate any of the copying.
I usually take the approach that any object in an STL container will
get copied and assigned quite a bit, and so try to make the object
itself as lightweight as possible.
In your case, how about making the vector reference-counted? That way
you could copy or assign the reference very cheaply. However you would
need to check that the reference was unique before any operation that
modified the vector, and if not then copy it prior to the operation
(this is the approach that many std::string implementations take). It's
quite a bit of work and not necessarily appropriate to your situation,
but worth considering. This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Chris Ochs |
last post by:
First of all, we are still running sapdb at the moment but are in the
process of moving to postgresql, so it seemed a good idea to post this type
of question here.
In our environment we have...
|
by: Steven D.Arnold |
last post by:
How good is Postgres' performance for massive simultaneous insertions
into the same heavily-indexed table? Are there any studies or
benchmarks I can look at for that?
I understand Postgres uses...
|
by: Dave Rudolf |
last post by:
Hi all,
Normally, I would trust that the ANSI libraries are written to be as
efficient as possible, but I have an application in which the majority of
the run time is calling the acos(...)...
|
by: Tomás |
last post by:
dynamic_cast can be used to obtain a pointer or to obtain a reference.
If the pointer form fails, then you're left with a null pointer.
If the reference form fails, then an exception is thrown....
|
by: extrudedaluminiu |
last post by:
Hi,
Is there any group in the manner of the C++ Boost group that works on
the evolution of the C language? Or is there any group that performs an
equivalent function?
Thanks,
-vs
|
by: simonZ |
last post by:
I create a transaction:
sqlTran=sqlConn.BeginTransaction(IsolationLevel.Serializable);
Then, I insert some data into report table with sqlCommand object:
oCmd = new...
|
by: vamshi |
last post by:
Hi all,
This is a question about the efficiency of the code.
a :-
int i;
for( i = 0; i < 20; i++ )
printf("%d",i);
b:-
int i = 10;
|
by: OldBirdman |
last post by:
Efficiency
I've never stumbled on any discussion of efficiency of various methods of coding, although I have found posts on various forums where individuals were concerned with efficiency. I'm...
|
by: want.to.be.professer |
last post by:
For OO design, I like using virtual member function.But considering
efficiency, template is better. Look at this program,
class Animal
{
public:
virtual void Walk() = 0;
};
class Dog
|
by: emmanuelkatto |
last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud.
Please let me know.
Thanks!
Emmanuel
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
by: Hystou |
last post by:
There are some requirements for setting up RAID:
1. The motherboard and BIOS support RAID configuration.
2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
|
by: Hystou |
last post by:
Overview:
Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
|
by: tracyyun |
last post by:
Dear forum friends,
With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
|
by: agi2029 |
last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
|
by: conductexam |
last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
| |