-
August 2nd, 2010, 07:19 PM
#1
A question regarding *s++
Suppose I define char* s, then I call *s++. I guess it should do ++ first and then dereference. But look at a very typical code,
Code:
char* s = "Hello";
char* s2 = new char[100];
char* p = s2;
while(*s)
{
*p++ = *s++;
}
*p = '\0';
Look at the statement *p++ = *s++, obviously p is deferenced first and then it is incremented. Is there anything I missed here? Thanks.
-
August 2nd, 2010, 08:12 PM
#2
Re: A question regarding *s++
It is actually incremented first. However, note that the postfix version of ++ is used, which means that while s itself is incremented, the return value of the operator is the old value of s.
That is,
Code:
char *s = "Hello";
// *s == 'H'
char *t = s++;
// *t == 'H', *s == 'e'
*t = 'h'
// now t points to "hello". Well, it doesn't, since modifying a string literal will probably crash the program, but it would if the Hello array had been in modifiable memory to begin with.
This behavior is the reason why prefix increment, ++s, should be preferred unless you have a specific need for the postfix version. It's not only less confusing, it can in some cases be more efficient.
-
August 2nd, 2010, 09:38 PM
#3
Re: A question regarding *s++
Thanks for your explainations.
Originally Posted by Lindley
It is actually incremented first. However, note that the postfix version of ++ is used, which means that while s itself is incremented, the return value of the operator is the old value of s.
That is,
Code:
char *s = "Hello";
// *s == 'H'
char *t = s++;
// *t == 'H', *s == 'e'
*t = 'h'
// now t points to "hello". Well, it doesn't, since modifying a string literal will probably crash the program, but it would if the Hello array had been in modifiable memory to begin with.
This behavior is the reason why prefix increment, ++s, should be preferred unless you have a specific need for the postfix version. It's not only less confusing, it can in some cases be more efficient.
-
August 2nd, 2010, 10:33 PM
#4
Re: A question regarding *s++
Originally Posted by Lindley
This behavior is the reason why prefix increment, ++s, should be preferred unless you have a specific need for the postfix version. It's not only less confusing, it can in some cases be more efficient.
Ok, now that we have a thread about that specific topic, I can ask this...
From plain old C I'm used to prefer the post-increment version unless it is specifically required otherwise, simply because it looks more familiar to me.
Am I right to assume that it wouldn't make a difference in terms of efficiency in C++ as long as it's about POD types?
It looks reasonable to me that I get a performance penalty if I use post-increment on non-POD types and I somehow process the result of that operation, because it is likely to require creation of a temporary object. But does it really make any difference if I don't use the result of the increment operation in further processing?
-
August 3rd, 2010, 01:29 AM
#5
Re: A question regarding *s++
Originally Posted by Eri523
Ok, now that we have a thread about that specific topic, I can ask this...
From plain old C I'm used to prefer the post-increment version unless it is specifically required otherwise, simply because it looks more familiar to me.
Am I right to assume that it wouldn't make a difference in terms of efficiency in C++ as long as it's about POD types?
It looks reasonable to me that I get a performance penalty if I use post-increment on non-POD types and I somehow process the result of that operation, because it is likely to require creation of a temporary object. But does it really make any difference if I don't use the result of the increment operation in further processing?
In a single sentence, "postfix is never faster, and sometimes slower".
Under these conditions, there really is no reason to use postfix unless you need to.
As for your question of taste ("prefering postfix over prefix"), if you start getting experience in C++, or work with people who have a C++ back ground, you will notice that prefix is the preferred way, and postfix will start looking weird.
PS: The compiler may or may not optimize away and performance penalty, but why take the chance?
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
August 3rd, 2010, 02:10 AM
#6
Re: A question regarding *s++
Originally Posted by Eri523
Ok, now that we have a thread about that specific topic, I can ask this...
From plain old C I'm used to prefer the post-increment version unless it is specifically required otherwise, simply because it looks more familiar to me.
Am I right to assume that it wouldn't make a difference in terms of efficiency in C++ as long as it's about POD types?
It looks reasonable to me that I get a performance penalty if I use post-increment on non-POD types and I somehow process the result of that operation, because it is likely to require creation of a temporary object. But does it really make any difference if I don't use the result of the increment operation in further processing?
The main argument for me to not using post-increment on class types isn't the possible lack of efficiency but that the behavior is different to that on POD types. Look at the following code (which was a C sample code in Stroustrup's Annotated C++ Reference)
Code:
while (*p++ = *q++);
When p and q are char arrays the above is a perfect strcpy. When p and q are class types there is no way to let the post-increment on the right-hand happen after the assignment.
If you then see that increment operation on class types mainly is done for containers and their iterators you probably will decide for prefix increment same as me and I promise that it will look 'more familiar' to you within a very short period ;-)
Regards, Alex
-
August 3rd, 2010, 02:51 AM
#7
Re: A question regarding *s++
Originally Posted by itsmeandnobodyelse
When p and q are class types there is no way to let the post-increment on the right-hand happen after the assignment.
Sorry, but I do not quite understand the problem that you are presenting. Now, order of evaluation is implementation defined, but here it seems quite clear that the dereference of q must happen before its post-increment. Therefore, how does it matter if the assignment happens before or after the post-increment? With the normally expected semantics, the net effect should be the same, i.e., similiar to "a perfect strcpy".
-
August 3rd, 2010, 03:40 AM
#8
Re: A question regarding *s++
Originally Posted by laserlight
Sorry, but I do not quite understand the problem that you are presenting. Now, order of evaluation is implementation defined, but here it seems quite clear that the dereference of q must happen before its post-increment. Therefore, how does it matter if the assignment happens before or after the post-increment? With the normally expected semantics, the net effect should be the same, i.e., similiar to "a perfect strcpy".
Assume
Code:
char p[20] = { '\0' };
char * q = "Hello";
while (*p++ = *q++);
The above does:
Code:
p[0] = 'H';
p[1] = 'e';
p[2] = 'l';
p[3] = 'l';
p[4] = 'o';
p[5] = '\0';
If you do the same with a string class
Code:
MyString q = "Hello";
while (*p++ = *q++);
which has pointer semantics and overloaded operators for derefence, assignment and post-increment
Code:
p[0] = 'e';
p[1] = 'l';
p[2] = 'l';
p[3] = 'o';
p[4]= '\0';
There is no way to happen the assigmnent *p = *q prior to the post-increment operation of q++.
Regards, Alex
-
August 3rd, 2010, 04:48 AM
#9
Re: A question regarding *s++
Originally Posted by itsmeandnobodyelse
There is no way to happen the assigmnent *p = *q prior to the post-increment operation of q++.
Regards, Alex
Maybe you are confusing evaluation order?
Regardless of type, when you write:
Both p++ and q++ are evaluated first (but in undefined relative order).
Once this is done, operator= is called on the return values of p++ and q++, ie, the old values of p and q. (making it look like the assignment took place before increment)
There is no special magic or rules that applies only to PODs that do the assignments first, and then increments the values of p or q.
...
Either that, or I seem to not understand what you are saying. Your example (rewritten since incomplete) seems to work correctly:
Code:
#include <iostream>
#include <string>
int main()
{
char pArray[20] = { '\0' };
char* p = pArray;
std::string helloStr = "Hello";
//force the null terminator into string //Undefined behavior, but defined in practice
helloStr.c_str();
std::string::iterator q = helloStr.begin();
while (*p++ = *q++); //note that this reads string.end(), but should point '\0'. May crash in ranged debug
std::cout << pArray << std::endl;
}
Was this your full example?
Regards,
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
August 3rd, 2010, 08:14 AM
#10
Re: A question regarding *s++
Originally Posted by monarch_dodra
Maybe you are confusing evaluation order?
Regardless of type, when you write:
Both p++ and q++ are evaluated first (but in undefined relative order).
Once this is done, operator= is called on the return values of p++ and q++, ie, the old values of p and q. (making it look like the assignment took place before increment)
There is no special magic or rules that applies only to PODs that do the assignments first, and then increments the values of p or q.
...
Either that, or I seem to not understand what you are saying. Your example (rewritten since incomplete) seems to work correctly:
Code:
#include <iostream>
#include <string>
int main()
{
char pArray[20] = { '\0' };
char* p = pArray;
std::string helloStr = "Hello";
//force the null terminator into string //Undefined behavior, but defined in practice
helloStr.c_str();
std::string::iterator q = helloStr.begin();
while (*p++ = *q++); //note that this reads string.end(), but should point '\0'. May crash in ranged debug
std::cout << pArray << std::endl;
}
Was this your full example?
Regards,
No, it was from my memories ;-)
Here is the code that compiles:
Code:
#include <iostream>
int main()
{
char * q = "Hello";
char buf[20] = { '\0' };
char * p = buf;
while (*p++ = *q++);
std::cout << buf << std::endl;
return 0;
}
If incrementation would happen before assignment the p[0] would not be set correctly.
I will add the string class example soonly.
Regards, Alex
-
August 3rd, 2010, 08:21 AM
#11
Re: A question regarding *s++
Originally Posted by itsmeandnobodyelse
If incrementation would happen before assignment the p[0] would not be set correctly.
Sure it would, given the post-increment semantics which are at the heart of what we're discussing.
-
August 3rd, 2010, 08:33 AM
#12
Re: A question regarding *s++
Here the full sample
Code:
#include<iostream>
class String
{
char * ps;
int siz;
int len;
public:
String(const char * psz)
{
siz = strlen(psz)+1;
ps = new char[siz];
strcpy(ps, psz);
}
~String() { delete []ps; }
const char * c_str() { return ps; }
friend class StringIterator;
};
class StringIterator
{
int pos;
String * s;
public:
StringIterator(String & str) : s(&str), pos(0) {}
char & operator*() { return s->ps[pos]; }
StringIterator& operator++(int)
{
pos++;
return *this;
}
};
int main()
{
char * q = "Hello";
char buf[20] = { '\0' };
char * p = buf;
while (*p++ = *q++);
std::cout << buf << std::endl;
String s("World");
String t(" ");
StringIterator i(s);
StringIterator j(t);
while (*j++ = *i++);
std::cout << t.c_str() << std::endl;
return 0;
}
And output is
Hello
orld
Regards, Alex
P.S.
I don't think the above is a real problem. However, it was that what invoked me to not using post-increment on class types anymore.
-
August 3rd, 2010, 08:07 AM
#13
Re: A question regarding *s++
Originally Posted by itsmeandnobodyelse
Assume
Code:
char p[20] = { '\0' };
char * q = "Hello";
while (*p++ = *q++);
I doubt that this would even compile: You are trying to increment an array.
-
August 3rd, 2010, 04:25 AM
#14
Re: A question regarding *s++
Originally Posted by laserlight
Sorry, but I do not quite understand the problem that you are presenting. Now, order of evaluation is implementation defined, but here it seems quite clear that the dereference of q must happen before its post-increment. Therefore, how does it matter if the assignment happens before or after the post-increment? With the normally expected semantics, the net effect should be the same, i.e., similiar to "a perfect strcpy".
I'm being pedantic, but since you rarely make a mistake, I thought I'd chip in here... the part in bold is not correct. The precedence of the post increment and post decrement operators is higher than the precedence of the dereference operator. Therefore for an ISO Standard compliant compiler the post increment must happen before the dereference.
-
August 3rd, 2010, 03:44 AM
#15
Re: A question regarding *s++
itsmeandnobodyelse: please provide the smallest and simplest compilable program that demonstrates what you claim.
EDIT:
This program appears to contradict your claims:
Code:
#include <iostream>
#include <deque>
class X
{
public:
explicit X(int n) : n(n) {}
// Sorry, I'm too lazy to use safe bool idiom,
// and explicit conversion functions might not yet be available to you.
operator bool() const
{
return n != 0;
}
int get() const
{
return n;
}
private:
int n;
};
int main()
{
using namespace std;
deque<X> one;
for (int i = 1; i <= 10; ++i)
{
one.push_back(X(i));
}
one.push_back(X(0));
deque<X> two(one.size(), X(-1));
deque<X>::iterator p = two.begin();
deque<X>::iterator q = one.begin();
while (*p++ = *q++);
for (deque<X>::size_type i = 0, size = two.size(); i < size; ++i)
{
cout << two[i].get() << endl;
}
}
The output I get is:
Code:
1
2
3
4
5
6
7
8
9
10
0
Last edited by laserlight; August 3rd, 2010 at 04:11 AM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|