Difference between string += s1 and string = string + s1 [closed]How many copy operations can move semantics save between 'string=string+s1' and 'string+=s1'?What is the difference between #include <filename> and #include “filename”?What are the differences between a pointer variable and a reference variable in C++?How do I iterate over the words of a string?Improve INSERT-per-second performance of SQLite?What is the difference between call and apply?String formatting: % vs. .formatIs the recommendation to include CSS before JavaScript invalid?Why does the order of the loops affect performance when iterating over a 2D array?Image Processing: Algorithm Improvement for 'Coca-Cola Can' RecognitionReplacing a 32-bit loop counter with 64-bit introduces crazy performance deviations
"Valet parking " or "parking valet"
Complaints from (junior) developers against solution architects: how can we show the benefits of our work and improve relationships?
Narset, Parter of Veils interaction with Matter Reshaper
What is this kind of symbol meant to be?
How do discovery writers hibernate?
Coworker mumbles to herself when working, how to ask her to stop?
Why tantalum for the Hayabusa bullets?
Create two random teams from a list of players
What are the cons of stateless password generators?
Why does one get the wrong value when printing counters together?
Scam? Checks via Email
How do I make my photos have more impact?
How did astronauts using rovers tell direction without compasses on the Moon?
Exploiting the delay when a festival ticket is scanned
Why are we moving in circles with a tandem kayak?
Solve equation using Mathematica
Avoiding Implicit Conversion in Constructor. Explicit keyword doesn't help here
What force enables us to walk? Friction or normal reaction?
Are all French verb conjugation tenses and moods practical and efficient?
Why don't short runways use ramps for takeoff?
What is my clock telling me to do?
Can machine learning learn a function like finding maximum from a list?
Why does Earth need water in the Expanse?
Efficiently finding furthest two nodes in a graph
Difference between string += s1 and string = string + s1 [closed]
How many copy operations can move semantics save between 'string=string+s1' and 'string+=s1'?What is the difference between #include <filename> and #include “filename”?What are the differences between a pointer variable and a reference variable in C++?How do I iterate over the words of a string?Improve INSERT-per-second performance of SQLite?What is the difference between call and apply?String formatting: % vs. .formatIs the recommendation to include CSS before JavaScript invalid?Why does the order of the loops affect performance when iterating over a 2D array?Image Processing: Algorithm Improvement for 'Coca-Cola Can' RecognitionReplacing a 32-bit loop counter with 64-bit introduces crazy performance deviations
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
One of my programs is exceeding the time limit when I am using fans = fans + s[i]
, while when I am using fans += s[i]
it is being accepted... Why does this happen?
To Explain more , fans is a string and s is also a string so while iterating over string s i want only some characters of s so i am creating a new string fans.Now there are two ways in which i can add character to my new string fans. The Problem is mentioned below
fans = fans + s[i]; // gives Time limit exceeded
fans += s[i]; // runs successfully
c++ performance stdstring compound-assignment
closed as off-topic by Ulrich Eckhardt, Daniel Kamil Kozar, Toby Speight, Matthieu M., Rory Daulton Jul 22 at 14:24
This question appears to be off-topic. The users who voted to close gave this specific reason:
- "Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a Minimal, Reproducible Example." – Ulrich Eckhardt, Daniel Kamil Kozar, Toby Speight, Matthieu M., Rory Daulton
|
show 6 more comments
One of my programs is exceeding the time limit when I am using fans = fans + s[i]
, while when I am using fans += s[i]
it is being accepted... Why does this happen?
To Explain more , fans is a string and s is also a string so while iterating over string s i want only some characters of s so i am creating a new string fans.Now there are two ways in which i can add character to my new string fans. The Problem is mentioned below
fans = fans + s[i]; // gives Time limit exceeded
fans += s[i]; // runs successfully
c++ performance stdstring compound-assignment
closed as off-topic by Ulrich Eckhardt, Daniel Kamil Kozar, Toby Speight, Matthieu M., Rory Daulton Jul 22 at 14:24
This question appears to be off-topic. The users who voted to close gave this specific reason:
- "Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a Minimal, Reproducible Example." – Ulrich Eckhardt, Daniel Kamil Kozar, Toby Speight, Matthieu M., Rory Daulton
1
One makes a temporary, the other doesn't. Move-assignment can make the former more efficient, but it can't get any better than the later.
– WhozCraig
Jul 21 at 10:38
7
Please extract and provide a minimal reproducible example, your question is off-topic without it. As a new user, also take the tour and read How to Ask.
– Ulrich Eckhardt
Jul 21 at 10:43
2
Sofans
is an std::string ands[i]
is a char? Or is it another string containing a single character?
– Fabio Turati
Jul 22 at 1:01
1
@Naman Have you read Ulrich Eckhardt's comment, and mine? At the very least you should clarify what typefans
ands[i]
are, but actually it would be better if you edited your question and added a full program (minimal reproducible example) that we can copy and compile. Just check the links that you've been given. It won't take long, and it will improve your question significantly. Thank you!
– Fabio Turati
Jul 23 at 0:45
1
You're not supposed to paste the code of the program you're working on. You are expected to extract a minimal reproducible example from that code and post that. It should be possible to take it and compile it without changes. It shouldn't contain anything that is not necessary to demonstrate the issue. Your question still lacks that, so it is still off-topic.
– Ulrich Eckhardt
Jul 24 at 16:31
|
show 6 more comments
One of my programs is exceeding the time limit when I am using fans = fans + s[i]
, while when I am using fans += s[i]
it is being accepted... Why does this happen?
To Explain more , fans is a string and s is also a string so while iterating over string s i want only some characters of s so i am creating a new string fans.Now there are two ways in which i can add character to my new string fans. The Problem is mentioned below
fans = fans + s[i]; // gives Time limit exceeded
fans += s[i]; // runs successfully
c++ performance stdstring compound-assignment
One of my programs is exceeding the time limit when I am using fans = fans + s[i]
, while when I am using fans += s[i]
it is being accepted... Why does this happen?
To Explain more , fans is a string and s is also a string so while iterating over string s i want only some characters of s so i am creating a new string fans.Now there are two ways in which i can add character to my new string fans. The Problem is mentioned below
fans = fans + s[i]; // gives Time limit exceeded
fans += s[i]; // runs successfully
c++ performance stdstring compound-assignment
c++ performance stdstring compound-assignment
edited Jul 24 at 4:25
Naman
asked Jul 21 at 10:33
NamanNaman
1361 silver badge12 bronze badges
1361 silver badge12 bronze badges
closed as off-topic by Ulrich Eckhardt, Daniel Kamil Kozar, Toby Speight, Matthieu M., Rory Daulton Jul 22 at 14:24
This question appears to be off-topic. The users who voted to close gave this specific reason:
- "Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a Minimal, Reproducible Example." – Ulrich Eckhardt, Daniel Kamil Kozar, Toby Speight, Matthieu M., Rory Daulton
closed as off-topic by Ulrich Eckhardt, Daniel Kamil Kozar, Toby Speight, Matthieu M., Rory Daulton Jul 22 at 14:24
This question appears to be off-topic. The users who voted to close gave this specific reason:
- "Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a Minimal, Reproducible Example." – Ulrich Eckhardt, Daniel Kamil Kozar, Toby Speight, Matthieu M., Rory Daulton
closed as off-topic by Ulrich Eckhardt, Daniel Kamil Kozar, Toby Speight, Matthieu M., Rory Daulton Jul 22 at 14:24
This question appears to be off-topic. The users who voted to close gave this specific reason:
- "Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a Minimal, Reproducible Example." – Ulrich Eckhardt, Daniel Kamil Kozar, Toby Speight, Matthieu M., Rory Daulton
1
One makes a temporary, the other doesn't. Move-assignment can make the former more efficient, but it can't get any better than the later.
– WhozCraig
Jul 21 at 10:38
7
Please extract and provide a minimal reproducible example, your question is off-topic without it. As a new user, also take the tour and read How to Ask.
– Ulrich Eckhardt
Jul 21 at 10:43
2
Sofans
is an std::string ands[i]
is a char? Or is it another string containing a single character?
– Fabio Turati
Jul 22 at 1:01
1
@Naman Have you read Ulrich Eckhardt's comment, and mine? At the very least you should clarify what typefans
ands[i]
are, but actually it would be better if you edited your question and added a full program (minimal reproducible example) that we can copy and compile. Just check the links that you've been given. It won't take long, and it will improve your question significantly. Thank you!
– Fabio Turati
Jul 23 at 0:45
1
You're not supposed to paste the code of the program you're working on. You are expected to extract a minimal reproducible example from that code and post that. It should be possible to take it and compile it without changes. It shouldn't contain anything that is not necessary to demonstrate the issue. Your question still lacks that, so it is still off-topic.
– Ulrich Eckhardt
Jul 24 at 16:31
|
show 6 more comments
1
One makes a temporary, the other doesn't. Move-assignment can make the former more efficient, but it can't get any better than the later.
– WhozCraig
Jul 21 at 10:38
7
Please extract and provide a minimal reproducible example, your question is off-topic without it. As a new user, also take the tour and read How to Ask.
– Ulrich Eckhardt
Jul 21 at 10:43
2
Sofans
is an std::string ands[i]
is a char? Or is it another string containing a single character?
– Fabio Turati
Jul 22 at 1:01
1
@Naman Have you read Ulrich Eckhardt's comment, and mine? At the very least you should clarify what typefans
ands[i]
are, but actually it would be better if you edited your question and added a full program (minimal reproducible example) that we can copy and compile. Just check the links that you've been given. It won't take long, and it will improve your question significantly. Thank you!
– Fabio Turati
Jul 23 at 0:45
1
You're not supposed to paste the code of the program you're working on. You are expected to extract a minimal reproducible example from that code and post that. It should be possible to take it and compile it without changes. It shouldn't contain anything that is not necessary to demonstrate the issue. Your question still lacks that, so it is still off-topic.
– Ulrich Eckhardt
Jul 24 at 16:31
1
1
One makes a temporary, the other doesn't. Move-assignment can make the former more efficient, but it can't get any better than the later.
– WhozCraig
Jul 21 at 10:38
One makes a temporary, the other doesn't. Move-assignment can make the former more efficient, but it can't get any better than the later.
– WhozCraig
Jul 21 at 10:38
7
7
Please extract and provide a minimal reproducible example, your question is off-topic without it. As a new user, also take the tour and read How to Ask.
– Ulrich Eckhardt
Jul 21 at 10:43
Please extract and provide a minimal reproducible example, your question is off-topic without it. As a new user, also take the tour and read How to Ask.
– Ulrich Eckhardt
Jul 21 at 10:43
2
2
So
fans
is an std::string and s[i]
is a char? Or is it another string containing a single character?– Fabio Turati
Jul 22 at 1:01
So
fans
is an std::string and s[i]
is a char? Or is it another string containing a single character?– Fabio Turati
Jul 22 at 1:01
1
1
@Naman Have you read Ulrich Eckhardt's comment, and mine? At the very least you should clarify what type
fans
and s[i]
are, but actually it would be better if you edited your question and added a full program (minimal reproducible example) that we can copy and compile. Just check the links that you've been given. It won't take long, and it will improve your question significantly. Thank you!– Fabio Turati
Jul 23 at 0:45
@Naman Have you read Ulrich Eckhardt's comment, and mine? At the very least you should clarify what type
fans
and s[i]
are, but actually it would be better if you edited your question and added a full program (minimal reproducible example) that we can copy and compile. Just check the links that you've been given. It won't take long, and it will improve your question significantly. Thank you!– Fabio Turati
Jul 23 at 0:45
1
1
You're not supposed to paste the code of the program you're working on. You are expected to extract a minimal reproducible example from that code and post that. It should be possible to take it and compile it without changes. It shouldn't contain anything that is not necessary to demonstrate the issue. Your question still lacks that, so it is still off-topic.
– Ulrich Eckhardt
Jul 24 at 16:31
You're not supposed to paste the code of the program you're working on. You are expected to extract a minimal reproducible example from that code and post that. It should be possible to take it and compile it without changes. It shouldn't contain anything that is not necessary to demonstrate the issue. Your question still lacks that, so it is still off-topic.
– Ulrich Eckhardt
Jul 24 at 16:31
|
show 6 more comments
4 Answers
4
active
oldest
votes
For built-in types a += b
is exactly the same as a = a + b
, but for classes, those operators are overloaded and call different functions.
In your example fans = fans + s[i]
creates a temporary string, and assigns (moves) it to fans
, but fans += s[i]
does not create that temporary, hence it may be faster.
2
"+=" may also cause a relocation if the string size is already as big as the preallocated buffer. If later on this turns out to be a problem (of course this should be measured), and if the size may be estimated in advance, the buffer size may be increased explicitly using string::reserve().
– IMil
Jul 22 at 2:07
@IMil In fact, depending on how the implementation handles allocation, it's quite possible that there's no difference between the two methods, isn't it? With a naive implementation I'd expect that both methods take almost exactly the same time (the time of 1 allocation).
– MC ΔT
Jul 22 at 4:21
1
@MCΔT that's right. So, it would make sense to suggest to the OP that if performance is an issue, one should understand how standard containers work and what they do and don't guarantee in terms of speed and memory. Modifying an std::string inside a tight loop is definitely wasteful, but without knowing context it's hard to suggest replacement.
– IMil
Jul 22 at 4:38
add a comment |
std::string
has members operator +
and operator +=
. The former is usually implemented with the latter by way of an intermediate temporary. Effectively looking something like this (check your implementation source if you want to know exactly what yours does):
/// note reference return type
std::string& operator +=(char c)
this->append(c);
return *this;
// note value return type
std::string operator +(char c) const
std::string tmp = *this;
tmp += c; // or just tmp.append(c) directly
return tmp;
The setup of tmp
is expensive. The overall function can (and usually is) made better with move-assignment semantics to the final destination on the caller-side, but the expense of the temporary is none-the-less still there. Do it a few times and you won't notice the difference. Do it thousands, or millions, etc. of times, and it can mean a world of difference.
Implementingstring+anything
orstring+=anything
in terms of the other looks to always be inefficient (one allocation and deallocation too much). Are you sure there are implementations doing that?
– Deduplicator
Jul 21 at 20:24
@Deduplicator+=
is usually the more efficient of the two (though there may be outliers). It is relatively common to implement+
by calling+=
as above, and this does not incur any significant overhead. Both operators typically accept their RHS argument by const reference (if it is something non-trivial), so there is no extra copying of that argument, merely plain function call overhead -- and even that will often be eliminated if the compiler inlines it. Similarly NRVO or one of its friends means thatoperator+
only creates one temporary, not two.
– Miral
Jul 22 at 6:49
1
@Miral Let's go through it, ok? += using +, the string will be newly allocated, using any extra capacity available is impossible. + using +=, the string will allocate for a copy of the lhs, and must then reallocate to accomodate the rhs too. With types where addition is not concatenation one generally doesn't have that problem, but this is about strings featuring a capacity, specificallystd::string
.
– Deduplicator
Jul 22 at 8:51
As I said, normally you would not implement+=
by calling+
, because that is completely inefficient. For+
calling+=
, yes, you're correct that the exact implementation above is not as efficient as it could be, since it might allocate twice (but if the appended rhs fits into the capacity of the lhs, then that won't happen). For efficiency a different implementation would commonly be used in practice which reserves the appended size before calling+=
(or the moral equivalent). That was outside the scope of this answer, though.
– Miral
Jul 22 at 23:47
add a comment |
If you use fans=fans+s[i]
, the string will be copied in every loop pass. The new element will be added to the copy of the string and the result will be reassigned to the variable fans
. After this the old string will have to be removed because it is not referenced anymore. This takes a whole lot of time.
If you use the augmented assignment fans+=s[i]
the string will not be copied in every loop pass and there is no need of removing the reference variable as there is no reference variable here. This saves a lot of time.
I hope now you can understand!!
In modern C++ there is no need to "copy" the string - move semantics can apply.
– Alnitak
Jul 22 at 12:32
@Alnitak, I believe move semantics can makestring = string + s1
better than without move semantics, but not as good asstring += s1
. I believe the former will always have at least one allocation and one full copy of all of the bytes of bothstring
ands1
, while the latter (string += s1
) copies only the bytes ofs1
and does not make any extra allocation (as long as the result can fit in the already-allocated capacity ofstring
). Please see my related post [stackoverflow.com/q/57151379/1245420] and if I'm wrong, please correct me!
– phonetagger
Jul 22 at 18:21
@phonetagger I was alluding to the additional copy caused by the=
operator without move semantics available. With move semantics, the result of string + s1 can be reassigned to string without copy overhead. But yes, there'd be a temporary created to makestring + s1
in the first place, which does also involve a copy operation.
– Alnitak
Jul 23 at 10:08
Infans = fans + s[i]
, the result ofoperator+
must materialize a temporary object ; which can be moved out of intofans
, but this still necessitates a complete copy of the original content offans
existing simultaneously with the original content, until this move happens and then the original content is discarded
– M.M
Jul 24 at 4:33
add a comment |
For fundamental types, a = a + b
and a += b
mean the same thing.
For arbitrary class types, a = a + b
and a += b
are unrelated; they look up different operators, and those operators can do arbitrary things. Them being actually unrelated is code smell, a sign of a design problem.
a = a + b
becomes operator=( a, operator+( a, b ) )
roughly; the actual lookup rules are a bit more complex (involving member operators and non-member operators, and the fact that =
doesn't have a non-member operator, etc), but that is the core of it.
a += b
becomes operator+=( a, b )
in a similar sense.
Now, it is a common pattern to implement +
in terms of +=
; if you do this, you get:
a = a + b
becomes
a = ((auto)(a) += b);
where (auto)
is the new c++20/c++23 "create a temporary copy of the argument" feature.
Fundamentally, a+=b
can reuse the contents of a
directly, while a = a + b
cannot; at the moment a+b
is evaluated, it doesn't know that a
will be soon overwritten.
Some libraries deal with this using a technique known as "expression templates"; a+b
isn't a value, but rather a compile-time description of the expression a+b
, which when assigned to a
is actually used to populate a
with data. With expression templates, the fundamental issue of a+=b
knowing more than a=a+b
is eliminated.
Now, for std::string
specifically, a+b
creates a temporary string object, then a=(a+b)
moves that into a
(it can reuse the buffer of the temporary string object or the buffer of a
, the standard is silent on this matter).
a+=b
must reuse any excess capacity in the a
buffer. So if you a.reserve(1<<30)
(1 billion), a+=b
cannot allocate more.
Could you link to further discussion of this new(auto)
feature?
– M.M
Jul 24 at 4:28
@m.m not discussion, but a paper: open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0849r1.html
– Yakk - Adam Nevraumont
Jul 24 at 10:35
Thanks. Probably should allowstatic_cast<auto>(x)
for consistency , i.e.T(x)
meansstatic_cast<T>(x)
and vice versa for everything else
– M.M
Jul 24 at 12:05
1
@M.MT(x)
does not meanstatic_cast<T>(x)
, nor vice versa, in general. It does sometimes. And I'd argue that verbosity here is a sin; C++ standard tends to be over verbose in initial versions of things, and we should fight against that tendency.
– Yakk - Adam Nevraumont
Jul 24 at 12:34
@Yakk-AdamNevraumont Can u help my question is put on hold , I have made the necessary changes than too nothing happened.Even though it has received many upvotes and answers
– Naman
Jul 24 at 13:51
add a comment |
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
For built-in types a += b
is exactly the same as a = a + b
, but for classes, those operators are overloaded and call different functions.
In your example fans = fans + s[i]
creates a temporary string, and assigns (moves) it to fans
, but fans += s[i]
does not create that temporary, hence it may be faster.
2
"+=" may also cause a relocation if the string size is already as big as the preallocated buffer. If later on this turns out to be a problem (of course this should be measured), and if the size may be estimated in advance, the buffer size may be increased explicitly using string::reserve().
– IMil
Jul 22 at 2:07
@IMil In fact, depending on how the implementation handles allocation, it's quite possible that there's no difference between the two methods, isn't it? With a naive implementation I'd expect that both methods take almost exactly the same time (the time of 1 allocation).
– MC ΔT
Jul 22 at 4:21
1
@MCΔT that's right. So, it would make sense to suggest to the OP that if performance is an issue, one should understand how standard containers work and what they do and don't guarantee in terms of speed and memory. Modifying an std::string inside a tight loop is definitely wasteful, but without knowing context it's hard to suggest replacement.
– IMil
Jul 22 at 4:38
add a comment |
For built-in types a += b
is exactly the same as a = a + b
, but for classes, those operators are overloaded and call different functions.
In your example fans = fans + s[i]
creates a temporary string, and assigns (moves) it to fans
, but fans += s[i]
does not create that temporary, hence it may be faster.
2
"+=" may also cause a relocation if the string size is already as big as the preallocated buffer. If later on this turns out to be a problem (of course this should be measured), and if the size may be estimated in advance, the buffer size may be increased explicitly using string::reserve().
– IMil
Jul 22 at 2:07
@IMil In fact, depending on how the implementation handles allocation, it's quite possible that there's no difference between the two methods, isn't it? With a naive implementation I'd expect that both methods take almost exactly the same time (the time of 1 allocation).
– MC ΔT
Jul 22 at 4:21
1
@MCΔT that's right. So, it would make sense to suggest to the OP that if performance is an issue, one should understand how standard containers work and what they do and don't guarantee in terms of speed and memory. Modifying an std::string inside a tight loop is definitely wasteful, but without knowing context it's hard to suggest replacement.
– IMil
Jul 22 at 4:38
add a comment |
For built-in types a += b
is exactly the same as a = a + b
, but for classes, those operators are overloaded and call different functions.
In your example fans = fans + s[i]
creates a temporary string, and assigns (moves) it to fans
, but fans += s[i]
does not create that temporary, hence it may be faster.
For built-in types a += b
is exactly the same as a = a + b
, but for classes, those operators are overloaded and call different functions.
In your example fans = fans + s[i]
creates a temporary string, and assigns (moves) it to fans
, but fans += s[i]
does not create that temporary, hence it may be faster.
answered Jul 21 at 10:45
AyxanAyxan
4,2991 gold badge10 silver badges35 bronze badges
4,2991 gold badge10 silver badges35 bronze badges
2
"+=" may also cause a relocation if the string size is already as big as the preallocated buffer. If later on this turns out to be a problem (of course this should be measured), and if the size may be estimated in advance, the buffer size may be increased explicitly using string::reserve().
– IMil
Jul 22 at 2:07
@IMil In fact, depending on how the implementation handles allocation, it's quite possible that there's no difference between the two methods, isn't it? With a naive implementation I'd expect that both methods take almost exactly the same time (the time of 1 allocation).
– MC ΔT
Jul 22 at 4:21
1
@MCΔT that's right. So, it would make sense to suggest to the OP that if performance is an issue, one should understand how standard containers work and what they do and don't guarantee in terms of speed and memory. Modifying an std::string inside a tight loop is definitely wasteful, but without knowing context it's hard to suggest replacement.
– IMil
Jul 22 at 4:38
add a comment |
2
"+=" may also cause a relocation if the string size is already as big as the preallocated buffer. If later on this turns out to be a problem (of course this should be measured), and if the size may be estimated in advance, the buffer size may be increased explicitly using string::reserve().
– IMil
Jul 22 at 2:07
@IMil In fact, depending on how the implementation handles allocation, it's quite possible that there's no difference between the two methods, isn't it? With a naive implementation I'd expect that both methods take almost exactly the same time (the time of 1 allocation).
– MC ΔT
Jul 22 at 4:21
1
@MCΔT that's right. So, it would make sense to suggest to the OP that if performance is an issue, one should understand how standard containers work and what they do and don't guarantee in terms of speed and memory. Modifying an std::string inside a tight loop is definitely wasteful, but without knowing context it's hard to suggest replacement.
– IMil
Jul 22 at 4:38
2
2
"+=" may also cause a relocation if the string size is already as big as the preallocated buffer. If later on this turns out to be a problem (of course this should be measured), and if the size may be estimated in advance, the buffer size may be increased explicitly using string::reserve().
– IMil
Jul 22 at 2:07
"+=" may also cause a relocation if the string size is already as big as the preallocated buffer. If later on this turns out to be a problem (of course this should be measured), and if the size may be estimated in advance, the buffer size may be increased explicitly using string::reserve().
– IMil
Jul 22 at 2:07
@IMil In fact, depending on how the implementation handles allocation, it's quite possible that there's no difference between the two methods, isn't it? With a naive implementation I'd expect that both methods take almost exactly the same time (the time of 1 allocation).
– MC ΔT
Jul 22 at 4:21
@IMil In fact, depending on how the implementation handles allocation, it's quite possible that there's no difference between the two methods, isn't it? With a naive implementation I'd expect that both methods take almost exactly the same time (the time of 1 allocation).
– MC ΔT
Jul 22 at 4:21
1
1
@MCΔT that's right. So, it would make sense to suggest to the OP that if performance is an issue, one should understand how standard containers work and what they do and don't guarantee in terms of speed and memory. Modifying an std::string inside a tight loop is definitely wasteful, but without knowing context it's hard to suggest replacement.
– IMil
Jul 22 at 4:38
@MCΔT that's right. So, it would make sense to suggest to the OP that if performance is an issue, one should understand how standard containers work and what they do and don't guarantee in terms of speed and memory. Modifying an std::string inside a tight loop is definitely wasteful, but without knowing context it's hard to suggest replacement.
– IMil
Jul 22 at 4:38
add a comment |
std::string
has members operator +
and operator +=
. The former is usually implemented with the latter by way of an intermediate temporary. Effectively looking something like this (check your implementation source if you want to know exactly what yours does):
/// note reference return type
std::string& operator +=(char c)
this->append(c);
return *this;
// note value return type
std::string operator +(char c) const
std::string tmp = *this;
tmp += c; // or just tmp.append(c) directly
return tmp;
The setup of tmp
is expensive. The overall function can (and usually is) made better with move-assignment semantics to the final destination on the caller-side, but the expense of the temporary is none-the-less still there. Do it a few times and you won't notice the difference. Do it thousands, or millions, etc. of times, and it can mean a world of difference.
Implementingstring+anything
orstring+=anything
in terms of the other looks to always be inefficient (one allocation and deallocation too much). Are you sure there are implementations doing that?
– Deduplicator
Jul 21 at 20:24
@Deduplicator+=
is usually the more efficient of the two (though there may be outliers). It is relatively common to implement+
by calling+=
as above, and this does not incur any significant overhead. Both operators typically accept their RHS argument by const reference (if it is something non-trivial), so there is no extra copying of that argument, merely plain function call overhead -- and even that will often be eliminated if the compiler inlines it. Similarly NRVO or one of its friends means thatoperator+
only creates one temporary, not two.
– Miral
Jul 22 at 6:49
1
@Miral Let's go through it, ok? += using +, the string will be newly allocated, using any extra capacity available is impossible. + using +=, the string will allocate for a copy of the lhs, and must then reallocate to accomodate the rhs too. With types where addition is not concatenation one generally doesn't have that problem, but this is about strings featuring a capacity, specificallystd::string
.
– Deduplicator
Jul 22 at 8:51
As I said, normally you would not implement+=
by calling+
, because that is completely inefficient. For+
calling+=
, yes, you're correct that the exact implementation above is not as efficient as it could be, since it might allocate twice (but if the appended rhs fits into the capacity of the lhs, then that won't happen). For efficiency a different implementation would commonly be used in practice which reserves the appended size before calling+=
(or the moral equivalent). That was outside the scope of this answer, though.
– Miral
Jul 22 at 23:47
add a comment |
std::string
has members operator +
and operator +=
. The former is usually implemented with the latter by way of an intermediate temporary. Effectively looking something like this (check your implementation source if you want to know exactly what yours does):
/// note reference return type
std::string& operator +=(char c)
this->append(c);
return *this;
// note value return type
std::string operator +(char c) const
std::string tmp = *this;
tmp += c; // or just tmp.append(c) directly
return tmp;
The setup of tmp
is expensive. The overall function can (and usually is) made better with move-assignment semantics to the final destination on the caller-side, but the expense of the temporary is none-the-less still there. Do it a few times and you won't notice the difference. Do it thousands, or millions, etc. of times, and it can mean a world of difference.
Implementingstring+anything
orstring+=anything
in terms of the other looks to always be inefficient (one allocation and deallocation too much). Are you sure there are implementations doing that?
– Deduplicator
Jul 21 at 20:24
@Deduplicator+=
is usually the more efficient of the two (though there may be outliers). It is relatively common to implement+
by calling+=
as above, and this does not incur any significant overhead. Both operators typically accept their RHS argument by const reference (if it is something non-trivial), so there is no extra copying of that argument, merely plain function call overhead -- and even that will often be eliminated if the compiler inlines it. Similarly NRVO or one of its friends means thatoperator+
only creates one temporary, not two.
– Miral
Jul 22 at 6:49
1
@Miral Let's go through it, ok? += using +, the string will be newly allocated, using any extra capacity available is impossible. + using +=, the string will allocate for a copy of the lhs, and must then reallocate to accomodate the rhs too. With types where addition is not concatenation one generally doesn't have that problem, but this is about strings featuring a capacity, specificallystd::string
.
– Deduplicator
Jul 22 at 8:51
As I said, normally you would not implement+=
by calling+
, because that is completely inefficient. For+
calling+=
, yes, you're correct that the exact implementation above is not as efficient as it could be, since it might allocate twice (but if the appended rhs fits into the capacity of the lhs, then that won't happen). For efficiency a different implementation would commonly be used in practice which reserves the appended size before calling+=
(or the moral equivalent). That was outside the scope of this answer, though.
– Miral
Jul 22 at 23:47
add a comment |
std::string
has members operator +
and operator +=
. The former is usually implemented with the latter by way of an intermediate temporary. Effectively looking something like this (check your implementation source if you want to know exactly what yours does):
/// note reference return type
std::string& operator +=(char c)
this->append(c);
return *this;
// note value return type
std::string operator +(char c) const
std::string tmp = *this;
tmp += c; // or just tmp.append(c) directly
return tmp;
The setup of tmp
is expensive. The overall function can (and usually is) made better with move-assignment semantics to the final destination on the caller-side, but the expense of the temporary is none-the-less still there. Do it a few times and you won't notice the difference. Do it thousands, or millions, etc. of times, and it can mean a world of difference.
std::string
has members operator +
and operator +=
. The former is usually implemented with the latter by way of an intermediate temporary. Effectively looking something like this (check your implementation source if you want to know exactly what yours does):
/// note reference return type
std::string& operator +=(char c)
this->append(c);
return *this;
// note value return type
std::string operator +(char c) const
std::string tmp = *this;
tmp += c; // or just tmp.append(c) directly
return tmp;
The setup of tmp
is expensive. The overall function can (and usually is) made better with move-assignment semantics to the final destination on the caller-side, but the expense of the temporary is none-the-less still there. Do it a few times and you won't notice the difference. Do it thousands, or millions, etc. of times, and it can mean a world of difference.
answered Jul 21 at 10:51
WhozCraigWhozCraig
52.9k9 gold badges61 silver badges110 bronze badges
52.9k9 gold badges61 silver badges110 bronze badges
Implementingstring+anything
orstring+=anything
in terms of the other looks to always be inefficient (one allocation and deallocation too much). Are you sure there are implementations doing that?
– Deduplicator
Jul 21 at 20:24
@Deduplicator+=
is usually the more efficient of the two (though there may be outliers). It is relatively common to implement+
by calling+=
as above, and this does not incur any significant overhead. Both operators typically accept their RHS argument by const reference (if it is something non-trivial), so there is no extra copying of that argument, merely plain function call overhead -- and even that will often be eliminated if the compiler inlines it. Similarly NRVO or one of its friends means thatoperator+
only creates one temporary, not two.
– Miral
Jul 22 at 6:49
1
@Miral Let's go through it, ok? += using +, the string will be newly allocated, using any extra capacity available is impossible. + using +=, the string will allocate for a copy of the lhs, and must then reallocate to accomodate the rhs too. With types where addition is not concatenation one generally doesn't have that problem, but this is about strings featuring a capacity, specificallystd::string
.
– Deduplicator
Jul 22 at 8:51
As I said, normally you would not implement+=
by calling+
, because that is completely inefficient. For+
calling+=
, yes, you're correct that the exact implementation above is not as efficient as it could be, since it might allocate twice (but if the appended rhs fits into the capacity of the lhs, then that won't happen). For efficiency a different implementation would commonly be used in practice which reserves the appended size before calling+=
(or the moral equivalent). That was outside the scope of this answer, though.
– Miral
Jul 22 at 23:47
add a comment |
Implementingstring+anything
orstring+=anything
in terms of the other looks to always be inefficient (one allocation and deallocation too much). Are you sure there are implementations doing that?
– Deduplicator
Jul 21 at 20:24
@Deduplicator+=
is usually the more efficient of the two (though there may be outliers). It is relatively common to implement+
by calling+=
as above, and this does not incur any significant overhead. Both operators typically accept their RHS argument by const reference (if it is something non-trivial), so there is no extra copying of that argument, merely plain function call overhead -- and even that will often be eliminated if the compiler inlines it. Similarly NRVO or one of its friends means thatoperator+
only creates one temporary, not two.
– Miral
Jul 22 at 6:49
1
@Miral Let's go through it, ok? += using +, the string will be newly allocated, using any extra capacity available is impossible. + using +=, the string will allocate for a copy of the lhs, and must then reallocate to accomodate the rhs too. With types where addition is not concatenation one generally doesn't have that problem, but this is about strings featuring a capacity, specificallystd::string
.
– Deduplicator
Jul 22 at 8:51
As I said, normally you would not implement+=
by calling+
, because that is completely inefficient. For+
calling+=
, yes, you're correct that the exact implementation above is not as efficient as it could be, since it might allocate twice (but if the appended rhs fits into the capacity of the lhs, then that won't happen). For efficiency a different implementation would commonly be used in practice which reserves the appended size before calling+=
(or the moral equivalent). That was outside the scope of this answer, though.
– Miral
Jul 22 at 23:47
Implementing
string+anything
or string+=anything
in terms of the other looks to always be inefficient (one allocation and deallocation too much). Are you sure there are implementations doing that?– Deduplicator
Jul 21 at 20:24
Implementing
string+anything
or string+=anything
in terms of the other looks to always be inefficient (one allocation and deallocation too much). Are you sure there are implementations doing that?– Deduplicator
Jul 21 at 20:24
@Deduplicator
+=
is usually the more efficient of the two (though there may be outliers). It is relatively common to implement +
by calling +=
as above, and this does not incur any significant overhead. Both operators typically accept their RHS argument by const reference (if it is something non-trivial), so there is no extra copying of that argument, merely plain function call overhead -- and even that will often be eliminated if the compiler inlines it. Similarly NRVO or one of its friends means that operator+
only creates one temporary, not two.– Miral
Jul 22 at 6:49
@Deduplicator
+=
is usually the more efficient of the two (though there may be outliers). It is relatively common to implement +
by calling +=
as above, and this does not incur any significant overhead. Both operators typically accept their RHS argument by const reference (if it is something non-trivial), so there is no extra copying of that argument, merely plain function call overhead -- and even that will often be eliminated if the compiler inlines it. Similarly NRVO or one of its friends means that operator+
only creates one temporary, not two.– Miral
Jul 22 at 6:49
1
1
@Miral Let's go through it, ok? += using +, the string will be newly allocated, using any extra capacity available is impossible. + using +=, the string will allocate for a copy of the lhs, and must then reallocate to accomodate the rhs too. With types where addition is not concatenation one generally doesn't have that problem, but this is about strings featuring a capacity, specifically
std::string
.– Deduplicator
Jul 22 at 8:51
@Miral Let's go through it, ok? += using +, the string will be newly allocated, using any extra capacity available is impossible. + using +=, the string will allocate for a copy of the lhs, and must then reallocate to accomodate the rhs too. With types where addition is not concatenation one generally doesn't have that problem, but this is about strings featuring a capacity, specifically
std::string
.– Deduplicator
Jul 22 at 8:51
As I said, normally you would not implement
+=
by calling +
, because that is completely inefficient. For +
calling +=
, yes, you're correct that the exact implementation above is not as efficient as it could be, since it might allocate twice (but if the appended rhs fits into the capacity of the lhs, then that won't happen). For efficiency a different implementation would commonly be used in practice which reserves the appended size before calling +=
(or the moral equivalent). That was outside the scope of this answer, though.– Miral
Jul 22 at 23:47
As I said, normally you would not implement
+=
by calling +
, because that is completely inefficient. For +
calling +=
, yes, you're correct that the exact implementation above is not as efficient as it could be, since it might allocate twice (but if the appended rhs fits into the capacity of the lhs, then that won't happen). For efficiency a different implementation would commonly be used in practice which reserves the appended size before calling +=
(or the moral equivalent). That was outside the scope of this answer, though.– Miral
Jul 22 at 23:47
add a comment |
If you use fans=fans+s[i]
, the string will be copied in every loop pass. The new element will be added to the copy of the string and the result will be reassigned to the variable fans
. After this the old string will have to be removed because it is not referenced anymore. This takes a whole lot of time.
If you use the augmented assignment fans+=s[i]
the string will not be copied in every loop pass and there is no need of removing the reference variable as there is no reference variable here. This saves a lot of time.
I hope now you can understand!!
In modern C++ there is no need to "copy" the string - move semantics can apply.
– Alnitak
Jul 22 at 12:32
@Alnitak, I believe move semantics can makestring = string + s1
better than without move semantics, but not as good asstring += s1
. I believe the former will always have at least one allocation and one full copy of all of the bytes of bothstring
ands1
, while the latter (string += s1
) copies only the bytes ofs1
and does not make any extra allocation (as long as the result can fit in the already-allocated capacity ofstring
). Please see my related post [stackoverflow.com/q/57151379/1245420] and if I'm wrong, please correct me!
– phonetagger
Jul 22 at 18:21
@phonetagger I was alluding to the additional copy caused by the=
operator without move semantics available. With move semantics, the result of string + s1 can be reassigned to string without copy overhead. But yes, there'd be a temporary created to makestring + s1
in the first place, which does also involve a copy operation.
– Alnitak
Jul 23 at 10:08
Infans = fans + s[i]
, the result ofoperator+
must materialize a temporary object ; which can be moved out of intofans
, but this still necessitates a complete copy of the original content offans
existing simultaneously with the original content, until this move happens and then the original content is discarded
– M.M
Jul 24 at 4:33
add a comment |
If you use fans=fans+s[i]
, the string will be copied in every loop pass. The new element will be added to the copy of the string and the result will be reassigned to the variable fans
. After this the old string will have to be removed because it is not referenced anymore. This takes a whole lot of time.
If you use the augmented assignment fans+=s[i]
the string will not be copied in every loop pass and there is no need of removing the reference variable as there is no reference variable here. This saves a lot of time.
I hope now you can understand!!
In modern C++ there is no need to "copy" the string - move semantics can apply.
– Alnitak
Jul 22 at 12:32
@Alnitak, I believe move semantics can makestring = string + s1
better than without move semantics, but not as good asstring += s1
. I believe the former will always have at least one allocation and one full copy of all of the bytes of bothstring
ands1
, while the latter (string += s1
) copies only the bytes ofs1
and does not make any extra allocation (as long as the result can fit in the already-allocated capacity ofstring
). Please see my related post [stackoverflow.com/q/57151379/1245420] and if I'm wrong, please correct me!
– phonetagger
Jul 22 at 18:21
@phonetagger I was alluding to the additional copy caused by the=
operator without move semantics available. With move semantics, the result of string + s1 can be reassigned to string without copy overhead. But yes, there'd be a temporary created to makestring + s1
in the first place, which does also involve a copy operation.
– Alnitak
Jul 23 at 10:08
Infans = fans + s[i]
, the result ofoperator+
must materialize a temporary object ; which can be moved out of intofans
, but this still necessitates a complete copy of the original content offans
existing simultaneously with the original content, until this move happens and then the original content is discarded
– M.M
Jul 24 at 4:33
add a comment |
If you use fans=fans+s[i]
, the string will be copied in every loop pass. The new element will be added to the copy of the string and the result will be reassigned to the variable fans
. After this the old string will have to be removed because it is not referenced anymore. This takes a whole lot of time.
If you use the augmented assignment fans+=s[i]
the string will not be copied in every loop pass and there is no need of removing the reference variable as there is no reference variable here. This saves a lot of time.
I hope now you can understand!!
If you use fans=fans+s[i]
, the string will be copied in every loop pass. The new element will be added to the copy of the string and the result will be reassigned to the variable fans
. After this the old string will have to be removed because it is not referenced anymore. This takes a whole lot of time.
If you use the augmented assignment fans+=s[i]
the string will not be copied in every loop pass and there is no need of removing the reference variable as there is no reference variable here. This saves a lot of time.
I hope now you can understand!!
edited Jul 22 at 9:43
yassin
5352 gold badges6 silver badges18 bronze badges
5352 gold badges6 silver badges18 bronze badges
answered Jul 21 at 11:00
Sahil SrivastavSahil Srivastav
871 bronze badge
871 bronze badge
In modern C++ there is no need to "copy" the string - move semantics can apply.
– Alnitak
Jul 22 at 12:32
@Alnitak, I believe move semantics can makestring = string + s1
better than without move semantics, but not as good asstring += s1
. I believe the former will always have at least one allocation and one full copy of all of the bytes of bothstring
ands1
, while the latter (string += s1
) copies only the bytes ofs1
and does not make any extra allocation (as long as the result can fit in the already-allocated capacity ofstring
). Please see my related post [stackoverflow.com/q/57151379/1245420] and if I'm wrong, please correct me!
– phonetagger
Jul 22 at 18:21
@phonetagger I was alluding to the additional copy caused by the=
operator without move semantics available. With move semantics, the result of string + s1 can be reassigned to string without copy overhead. But yes, there'd be a temporary created to makestring + s1
in the first place, which does also involve a copy operation.
– Alnitak
Jul 23 at 10:08
Infans = fans + s[i]
, the result ofoperator+
must materialize a temporary object ; which can be moved out of intofans
, but this still necessitates a complete copy of the original content offans
existing simultaneously with the original content, until this move happens and then the original content is discarded
– M.M
Jul 24 at 4:33
add a comment |
In modern C++ there is no need to "copy" the string - move semantics can apply.
– Alnitak
Jul 22 at 12:32
@Alnitak, I believe move semantics can makestring = string + s1
better than without move semantics, but not as good asstring += s1
. I believe the former will always have at least one allocation and one full copy of all of the bytes of bothstring
ands1
, while the latter (string += s1
) copies only the bytes ofs1
and does not make any extra allocation (as long as the result can fit in the already-allocated capacity ofstring
). Please see my related post [stackoverflow.com/q/57151379/1245420] and if I'm wrong, please correct me!
– phonetagger
Jul 22 at 18:21
@phonetagger I was alluding to the additional copy caused by the=
operator without move semantics available. With move semantics, the result of string + s1 can be reassigned to string without copy overhead. But yes, there'd be a temporary created to makestring + s1
in the first place, which does also involve a copy operation.
– Alnitak
Jul 23 at 10:08
Infans = fans + s[i]
, the result ofoperator+
must materialize a temporary object ; which can be moved out of intofans
, but this still necessitates a complete copy of the original content offans
existing simultaneously with the original content, until this move happens and then the original content is discarded
– M.M
Jul 24 at 4:33
In modern C++ there is no need to "copy" the string - move semantics can apply.
– Alnitak
Jul 22 at 12:32
In modern C++ there is no need to "copy" the string - move semantics can apply.
– Alnitak
Jul 22 at 12:32
@Alnitak, I believe move semantics can make
string = string + s1
better than without move semantics, but not as good as string += s1
. I believe the former will always have at least one allocation and one full copy of all of the bytes of both string
and s1
, while the latter (string += s1
) copies only the bytes of s1
and does not make any extra allocation (as long as the result can fit in the already-allocated capacity of string
). Please see my related post [stackoverflow.com/q/57151379/1245420] and if I'm wrong, please correct me!– phonetagger
Jul 22 at 18:21
@Alnitak, I believe move semantics can make
string = string + s1
better than without move semantics, but not as good as string += s1
. I believe the former will always have at least one allocation and one full copy of all of the bytes of both string
and s1
, while the latter (string += s1
) copies only the bytes of s1
and does not make any extra allocation (as long as the result can fit in the already-allocated capacity of string
). Please see my related post [stackoverflow.com/q/57151379/1245420] and if I'm wrong, please correct me!– phonetagger
Jul 22 at 18:21
@phonetagger I was alluding to the additional copy caused by the
=
operator without move semantics available. With move semantics, the result of string + s1 can be reassigned to string without copy overhead. But yes, there'd be a temporary created to make string + s1
in the first place, which does also involve a copy operation.– Alnitak
Jul 23 at 10:08
@phonetagger I was alluding to the additional copy caused by the
=
operator without move semantics available. With move semantics, the result of string + s1 can be reassigned to string without copy overhead. But yes, there'd be a temporary created to make string + s1
in the first place, which does also involve a copy operation.– Alnitak
Jul 23 at 10:08
In
fans = fans + s[i]
, the result of operator+
must materialize a temporary object ; which can be moved out of into fans
, but this still necessitates a complete copy of the original content of fans
existing simultaneously with the original content, until this move happens and then the original content is discarded– M.M
Jul 24 at 4:33
In
fans = fans + s[i]
, the result of operator+
must materialize a temporary object ; which can be moved out of into fans
, but this still necessitates a complete copy of the original content of fans
existing simultaneously with the original content, until this move happens and then the original content is discarded– M.M
Jul 24 at 4:33
add a comment |
For fundamental types, a = a + b
and a += b
mean the same thing.
For arbitrary class types, a = a + b
and a += b
are unrelated; they look up different operators, and those operators can do arbitrary things. Them being actually unrelated is code smell, a sign of a design problem.
a = a + b
becomes operator=( a, operator+( a, b ) )
roughly; the actual lookup rules are a bit more complex (involving member operators and non-member operators, and the fact that =
doesn't have a non-member operator, etc), but that is the core of it.
a += b
becomes operator+=( a, b )
in a similar sense.
Now, it is a common pattern to implement +
in terms of +=
; if you do this, you get:
a = a + b
becomes
a = ((auto)(a) += b);
where (auto)
is the new c++20/c++23 "create a temporary copy of the argument" feature.
Fundamentally, a+=b
can reuse the contents of a
directly, while a = a + b
cannot; at the moment a+b
is evaluated, it doesn't know that a
will be soon overwritten.
Some libraries deal with this using a technique known as "expression templates"; a+b
isn't a value, but rather a compile-time description of the expression a+b
, which when assigned to a
is actually used to populate a
with data. With expression templates, the fundamental issue of a+=b
knowing more than a=a+b
is eliminated.
Now, for std::string
specifically, a+b
creates a temporary string object, then a=(a+b)
moves that into a
(it can reuse the buffer of the temporary string object or the buffer of a
, the standard is silent on this matter).
a+=b
must reuse any excess capacity in the a
buffer. So if you a.reserve(1<<30)
(1 billion), a+=b
cannot allocate more.
Could you link to further discussion of this new(auto)
feature?
– M.M
Jul 24 at 4:28
@m.m not discussion, but a paper: open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0849r1.html
– Yakk - Adam Nevraumont
Jul 24 at 10:35
Thanks. Probably should allowstatic_cast<auto>(x)
for consistency , i.e.T(x)
meansstatic_cast<T>(x)
and vice versa for everything else
– M.M
Jul 24 at 12:05
1
@M.MT(x)
does not meanstatic_cast<T>(x)
, nor vice versa, in general. It does sometimes. And I'd argue that verbosity here is a sin; C++ standard tends to be over verbose in initial versions of things, and we should fight against that tendency.
– Yakk - Adam Nevraumont
Jul 24 at 12:34
@Yakk-AdamNevraumont Can u help my question is put on hold , I have made the necessary changes than too nothing happened.Even though it has received many upvotes and answers
– Naman
Jul 24 at 13:51
add a comment |
For fundamental types, a = a + b
and a += b
mean the same thing.
For arbitrary class types, a = a + b
and a += b
are unrelated; they look up different operators, and those operators can do arbitrary things. Them being actually unrelated is code smell, a sign of a design problem.
a = a + b
becomes operator=( a, operator+( a, b ) )
roughly; the actual lookup rules are a bit more complex (involving member operators and non-member operators, and the fact that =
doesn't have a non-member operator, etc), but that is the core of it.
a += b
becomes operator+=( a, b )
in a similar sense.
Now, it is a common pattern to implement +
in terms of +=
; if you do this, you get:
a = a + b
becomes
a = ((auto)(a) += b);
where (auto)
is the new c++20/c++23 "create a temporary copy of the argument" feature.
Fundamentally, a+=b
can reuse the contents of a
directly, while a = a + b
cannot; at the moment a+b
is evaluated, it doesn't know that a
will be soon overwritten.
Some libraries deal with this using a technique known as "expression templates"; a+b
isn't a value, but rather a compile-time description of the expression a+b
, which when assigned to a
is actually used to populate a
with data. With expression templates, the fundamental issue of a+=b
knowing more than a=a+b
is eliminated.
Now, for std::string
specifically, a+b
creates a temporary string object, then a=(a+b)
moves that into a
(it can reuse the buffer of the temporary string object or the buffer of a
, the standard is silent on this matter).
a+=b
must reuse any excess capacity in the a
buffer. So if you a.reserve(1<<30)
(1 billion), a+=b
cannot allocate more.
Could you link to further discussion of this new(auto)
feature?
– M.M
Jul 24 at 4:28
@m.m not discussion, but a paper: open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0849r1.html
– Yakk - Adam Nevraumont
Jul 24 at 10:35
Thanks. Probably should allowstatic_cast<auto>(x)
for consistency , i.e.T(x)
meansstatic_cast<T>(x)
and vice versa for everything else
– M.M
Jul 24 at 12:05
1
@M.MT(x)
does not meanstatic_cast<T>(x)
, nor vice versa, in general. It does sometimes. And I'd argue that verbosity here is a sin; C++ standard tends to be over verbose in initial versions of things, and we should fight against that tendency.
– Yakk - Adam Nevraumont
Jul 24 at 12:34
@Yakk-AdamNevraumont Can u help my question is put on hold , I have made the necessary changes than too nothing happened.Even though it has received many upvotes and answers
– Naman
Jul 24 at 13:51
add a comment |
For fundamental types, a = a + b
and a += b
mean the same thing.
For arbitrary class types, a = a + b
and a += b
are unrelated; they look up different operators, and those operators can do arbitrary things. Them being actually unrelated is code smell, a sign of a design problem.
a = a + b
becomes operator=( a, operator+( a, b ) )
roughly; the actual lookup rules are a bit more complex (involving member operators and non-member operators, and the fact that =
doesn't have a non-member operator, etc), but that is the core of it.
a += b
becomes operator+=( a, b )
in a similar sense.
Now, it is a common pattern to implement +
in terms of +=
; if you do this, you get:
a = a + b
becomes
a = ((auto)(a) += b);
where (auto)
is the new c++20/c++23 "create a temporary copy of the argument" feature.
Fundamentally, a+=b
can reuse the contents of a
directly, while a = a + b
cannot; at the moment a+b
is evaluated, it doesn't know that a
will be soon overwritten.
Some libraries deal with this using a technique known as "expression templates"; a+b
isn't a value, but rather a compile-time description of the expression a+b
, which when assigned to a
is actually used to populate a
with data. With expression templates, the fundamental issue of a+=b
knowing more than a=a+b
is eliminated.
Now, for std::string
specifically, a+b
creates a temporary string object, then a=(a+b)
moves that into a
(it can reuse the buffer of the temporary string object or the buffer of a
, the standard is silent on this matter).
a+=b
must reuse any excess capacity in the a
buffer. So if you a.reserve(1<<30)
(1 billion), a+=b
cannot allocate more.
For fundamental types, a = a + b
and a += b
mean the same thing.
For arbitrary class types, a = a + b
and a += b
are unrelated; they look up different operators, and those operators can do arbitrary things. Them being actually unrelated is code smell, a sign of a design problem.
a = a + b
becomes operator=( a, operator+( a, b ) )
roughly; the actual lookup rules are a bit more complex (involving member operators and non-member operators, and the fact that =
doesn't have a non-member operator, etc), but that is the core of it.
a += b
becomes operator+=( a, b )
in a similar sense.
Now, it is a common pattern to implement +
in terms of +=
; if you do this, you get:
a = a + b
becomes
a = ((auto)(a) += b);
where (auto)
is the new c++20/c++23 "create a temporary copy of the argument" feature.
Fundamentally, a+=b
can reuse the contents of a
directly, while a = a + b
cannot; at the moment a+b
is evaluated, it doesn't know that a
will be soon overwritten.
Some libraries deal with this using a technique known as "expression templates"; a+b
isn't a value, but rather a compile-time description of the expression a+b
, which when assigned to a
is actually used to populate a
with data. With expression templates, the fundamental issue of a+=b
knowing more than a=a+b
is eliminated.
Now, for std::string
specifically, a+b
creates a temporary string object, then a=(a+b)
moves that into a
(it can reuse the buffer of the temporary string object or the buffer of a
, the standard is silent on this matter).
a+=b
must reuse any excess capacity in the a
buffer. So if you a.reserve(1<<30)
(1 billion), a+=b
cannot allocate more.
answered Jul 22 at 13:39
Yakk - Adam NevraumontYakk - Adam Nevraumont
195k21 gold badges214 silver badges404 bronze badges
195k21 gold badges214 silver badges404 bronze badges
Could you link to further discussion of this new(auto)
feature?
– M.M
Jul 24 at 4:28
@m.m not discussion, but a paper: open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0849r1.html
– Yakk - Adam Nevraumont
Jul 24 at 10:35
Thanks. Probably should allowstatic_cast<auto>(x)
for consistency , i.e.T(x)
meansstatic_cast<T>(x)
and vice versa for everything else
– M.M
Jul 24 at 12:05
1
@M.MT(x)
does not meanstatic_cast<T>(x)
, nor vice versa, in general. It does sometimes. And I'd argue that verbosity here is a sin; C++ standard tends to be over verbose in initial versions of things, and we should fight against that tendency.
– Yakk - Adam Nevraumont
Jul 24 at 12:34
@Yakk-AdamNevraumont Can u help my question is put on hold , I have made the necessary changes than too nothing happened.Even though it has received many upvotes and answers
– Naman
Jul 24 at 13:51
add a comment |
Could you link to further discussion of this new(auto)
feature?
– M.M
Jul 24 at 4:28
@m.m not discussion, but a paper: open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0849r1.html
– Yakk - Adam Nevraumont
Jul 24 at 10:35
Thanks. Probably should allowstatic_cast<auto>(x)
for consistency , i.e.T(x)
meansstatic_cast<T>(x)
and vice versa for everything else
– M.M
Jul 24 at 12:05
1
@M.MT(x)
does not meanstatic_cast<T>(x)
, nor vice versa, in general. It does sometimes. And I'd argue that verbosity here is a sin; C++ standard tends to be over verbose in initial versions of things, and we should fight against that tendency.
– Yakk - Adam Nevraumont
Jul 24 at 12:34
@Yakk-AdamNevraumont Can u help my question is put on hold , I have made the necessary changes than too nothing happened.Even though it has received many upvotes and answers
– Naman
Jul 24 at 13:51
Could you link to further discussion of this new
(auto)
feature?– M.M
Jul 24 at 4:28
Could you link to further discussion of this new
(auto)
feature?– M.M
Jul 24 at 4:28
@m.m not discussion, but a paper: open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0849r1.html
– Yakk - Adam Nevraumont
Jul 24 at 10:35
@m.m not discussion, but a paper: open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0849r1.html
– Yakk - Adam Nevraumont
Jul 24 at 10:35
Thanks. Probably should allow
static_cast<auto>(x)
for consistency , i.e. T(x)
means static_cast<T>(x)
and vice versa for everything else– M.M
Jul 24 at 12:05
Thanks. Probably should allow
static_cast<auto>(x)
for consistency , i.e. T(x)
means static_cast<T>(x)
and vice versa for everything else– M.M
Jul 24 at 12:05
1
1
@M.M
T(x)
does not mean static_cast<T>(x)
, nor vice versa, in general. It does sometimes. And I'd argue that verbosity here is a sin; C++ standard tends to be over verbose in initial versions of things, and we should fight against that tendency.– Yakk - Adam Nevraumont
Jul 24 at 12:34
@M.M
T(x)
does not mean static_cast<T>(x)
, nor vice versa, in general. It does sometimes. And I'd argue that verbosity here is a sin; C++ standard tends to be over verbose in initial versions of things, and we should fight against that tendency.– Yakk - Adam Nevraumont
Jul 24 at 12:34
@Yakk-AdamNevraumont Can u help my question is put on hold , I have made the necessary changes than too nothing happened.Even though it has received many upvotes and answers
– Naman
Jul 24 at 13:51
@Yakk-AdamNevraumont Can u help my question is put on hold , I have made the necessary changes than too nothing happened.Even though it has received many upvotes and answers
– Naman
Jul 24 at 13:51
add a comment |
1
One makes a temporary, the other doesn't. Move-assignment can make the former more efficient, but it can't get any better than the later.
– WhozCraig
Jul 21 at 10:38
7
Please extract and provide a minimal reproducible example, your question is off-topic without it. As a new user, also take the tour and read How to Ask.
– Ulrich Eckhardt
Jul 21 at 10:43
2
So
fans
is an std::string ands[i]
is a char? Or is it another string containing a single character?– Fabio Turati
Jul 22 at 1:01
1
@Naman Have you read Ulrich Eckhardt's comment, and mine? At the very least you should clarify what type
fans
ands[i]
are, but actually it would be better if you edited your question and added a full program (minimal reproducible example) that we can copy and compile. Just check the links that you've been given. It won't take long, and it will improve your question significantly. Thank you!– Fabio Turati
Jul 23 at 0:45
1
You're not supposed to paste the code of the program you're working on. You are expected to extract a minimal reproducible example from that code and post that. It should be possible to take it and compile it without changes. It shouldn't contain anything that is not necessary to demonstrate the issue. Your question still lacks that, so it is still off-topic.
– Ulrich Eckhardt
Jul 24 at 16:31