473,397 Members | 2,056 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,397 software developers and data experts.

Differences in code implemented using this pointer and a variable THIS simulating this pointer

Why is the result different for the following set of two code snippets

Code without using this pointer

#include <string>
#include <iostream>
using namespace std;

struct X {
private:
int len;
char *ptr;
public:
int GetLen() {
return len;
}
char * GetPtr() {
return ptr;
}
X& Set(char *);
X& Cat(char *);
X& Copy(X&);
void Print();
};

X& X::Set(char *pc) {
len = strlen(pc);
ptr = new char[len];
strcpy(ptr, pc);
return *this;
}

X& X::Cat(char *pc) {
len += strlen(pc);
strcat(ptr,pc);
return *this;
}

X& X::Copy(X& x) {
Set(x.GetPtr());
return *this;
}

void X::Print() {
cout << ptr << endl;
}

int main() {
X xobj1;
xobj1.Set("abcd")
.Cat("efgh");

xobj1.Print();
X xobj2;
xobj2.Copy(xobj1)
.Cat("ijkl");

xobj2.Print();
}

Equivalent code, the THIS variable simulating the hidden use of this
pointer

#include <string>
#include <iostream>
using namespace std;

struct X {
private:
int len;
char *ptr;
public:
int GetLen (X* const THIS) {
return THIS->len;
}
char * GetPtr (X* const THIS) {
return THIS->ptr;
}
X& Set(X* const, char *);
X& Cat(X* const, char *);
X& Copy(X* const, X&);
void Print(X* const);
};

X& X::Set(X* const THIS, char *pc) {
THIS->len = strlen(pc);
THIS->ptr = new char[THIS->len];
strcpy(THIS->ptr, pc);
return *THIS;
}

X& X::Cat(X* const THIS, char *pc) {
THIS->len += strlen(pc);
strcat(THIS->ptr, pc);
return *THIS;
}

X& X::Copy(X* const THIS, X& x) {
THIS->Set(THIS, x.GetPtr(&x));
return *THIS;
}

void X::Print(X* const THIS) {
cout << THIS->ptr << endl;
}

int main() {
X xobj1;
xobj1.Set(&xobj1 , "abcd")
.Cat(&xobj1 , "efgh");

xobj1.Print(&xobj1);
X xobj2;
xobj2.Copy(&xobj2 , xobj1)
.Cat(&xobj2 , "ijkl");

xobj2.Print(&xobj2);
}
Both examples produce the following output:
abcdefgh
abcdefghijkl

They are different for some reason. Any comments would be appreciated.

Sep 27 '07 #1
9 1759
chikkubhai wrote:
Why is the result different for the following set of two code snippets

Code without using this pointer

#include <string>
#include <iostream>
using namespace std;

struct X {
private:
int len;
char *ptr;
public:
int GetLen() {
return len;
}
char * GetPtr() {
return ptr;
}
X& Set(char *);
X& Cat(char *);
X& Copy(X&);
void Print();
};

X& X::Set(char *pc) {
len = strlen(pc);
ptr = new char[len];
strcpy(ptr, pc);
return *this;
}

X& X::Cat(char *pc) {
len += strlen(pc);
strcat(ptr,pc);
return *this;
}

X& X::Copy(X& x) {
Set(x.GetPtr());
return *this;
}

void X::Print() {
cout << ptr << endl;
}

int main() {
X xobj1;
xobj1.Set("abcd")
.Cat("efgh");

xobj1.Print();
X xobj2;
xobj2.Copy(xobj1)
.Cat("ijkl");

xobj2.Print();
}

Equivalent code, the THIS variable simulating the hidden use of this
pointer

#include <string>
#include <iostream>
using namespace std;

struct X {
private:
int len;
char *ptr;
public:
int GetLen (X* const THIS) {
return THIS->len;
}
char * GetPtr (X* const THIS) {
return THIS->ptr;
}
X& Set(X* const, char *);
X& Cat(X* const, char *);
X& Copy(X* const, X&);
void Print(X* const);
};

X& X::Set(X* const THIS, char *pc) {
THIS->len = strlen(pc);
THIS->ptr = new char[THIS->len];
strcpy(THIS->ptr, pc);
return *THIS;
}

X& X::Cat(X* const THIS, char *pc) {
THIS->len += strlen(pc);
strcat(THIS->ptr, pc);
return *THIS;
}

X& X::Copy(X* const THIS, X& x) {
THIS->Set(THIS, x.GetPtr(&x));
return *THIS;
}

void X::Print(X* const THIS) {
cout << THIS->ptr << endl;
}

int main() {
X xobj1;
xobj1.Set(&xobj1 , "abcd")
.Cat(&xobj1 , "efgh");

xobj1.Print(&xobj1);
X xobj2;
xobj2.Copy(&xobj2 , xobj1)
.Cat(&xobj2 , "ijkl");

xobj2.Print(&xobj2);
}
Both examples produce the following output:
abcdefgh
abcdefghijkl

They are different for some reason. Any comments would be appreciated.
Undefined behavior (for both programs). Your code has an off-by-one error in
the allocation of the character buffer. You should use std::string.
Best

Kai-Uwe Bux

Sep 27 '07 #2
I didn't quite get you, as I have already included the string class
and compiled both code without any problem.

Sep 27 '07 #3
and using namespace std will take care of what you are mentioning in C+
+

Sep 27 '07 #4
chikkubhai wrote:

[too little]

Please quote enough context. This is not a chat room. Due to the news
protocol, you cannot assume that previous post of the thread are available
on the server.
I didn't quite get you, as I have already included the string class
You have included the header <string>, but you did not use it. You used
char* and the related functions. Probably, you meant to include <string.h>
or <cstring>.
and compiled both code without any problem.
That is because standard headers are allowed to pull other standard headers.
In your implementation, either <stringor <iostreamseems include
<cstring>. That is not guaranteed by the standard. Thus, your code has a
bug there, too.

As for the undefined behavior, look closely at the following lines:

X& X::Set(char *pc) {
len = strlen(pc);
ptr = new char[len];
strcpy(ptr, pc);
return *this;
}

There is your main bug.
Best

Kai-Uwe Bux
Sep 27 '07 #5
I did not quite get why you felt I was in a chat room. Take it easy.
When you mentioned that I have to use std::string I replied saying I
used using namespace std which will require me not to use std::string
anymore.

Anyways, what is or where is the off by one error? I still see the
correct output as
abcdefgh

followed by

abcdefghijkl

Sep 27 '07 #6
chikkubhai wrote:
I did not quite get why you felt I was in a chat room.
Because you behave like that. Please read the FAQ on netiquette in this
forum (especially on quoting). You are the one asking for help. Show a
little courtesy and follows local customs.
Take it easy.
When you mentioned that I have to use std::string I replied saying I
used using namespace std which will require me not to use std::string
anymore.
Such recastings of conversations are better dealt with by quoting.

Anyway, your point about std::string vs string is irrelevant since neither
appeared in the code you posted. Instead of std::string, you used char*.
When I say you should use std::string, I do not mean "std::string" instead
of "string" (and I could not have meant that, because there was no "string"
in your code), I meant use std::string instead of char*.
Anyways, what is or where is the off by o
ne error?

X& X::Set(char *pc) {
len = strlen(pc);
ptr = new char[len]; // <--- here, you are short one character
strcpy(ptr, pc);
return *this;
}
But fixing that, will still not make it work. There are much bigger issues:

#include <string>
should read

#include <cstring>
#include <iostream>
using namespace std;

struct X {
private:
* int len;
* char *ptr;
public:
* int GetLen() {
* * return len;
* }
* char * GetPtr() {
* * return ptr;
* }
Poor design: this allows client code to write beyond allocated memory.
Buffer overruns will come from this.
* X& Set(char *);
* X& Cat(char *);
* X& Copy(X&);
* void Print();
};
Your class does not disable copy-construction and assignment. However, it
handles neither correctly. Your Set method allocates memory that is never
freed. The class leaks memory big time.
>
X& X::Set(char *pc) {
* len = strlen(pc);
* ptr = new char[len];
Here is the off by 1 error.

Also, should Set() be called twice on the same object, memory allocated in
the first run is not freed.
* strcpy(ptr, pc);
* return *this;
}

X& X::Cat(char *pc) {
* len += strlen(pc);
* strcat(ptr,pc);
* return *this;
}
This is even worse: you append beyond allocated memory.
>
X& X::Copy(X& x) {
* Set(x.GetPtr());
* return *this;
}
void X::Print() {
* cout << ptr << endl;
}

int main() {
* X xobj1;
* xobj1.Set("abcd")
* * * *.Cat("efgh");

* xobj1.Print();
* X xobj2;
* xobj2.Copy(xobj1)
* * * *.Cat("ijkl");

* xobj2.Print();
}
All in all, you should not touch char*. There is no need to deal with char*
anyway since there is std::string. You should use it.

I still see the
correct output as
abcdefgh

followed by

abcdefghijkl
Undefined behavior sometimes looks correct and sometimes looks wrong.
Best

Kai-Uwe Bux
Sep 27 '07 #7
On Sep 27, 12:01 am, Kai-Uwe Bux <jkherci...@gmx.netwrote:
chikkubhai wrote:
I did not quite get why you felt I was in a chat room.

Because you behave like that. Please read the FAQ on netiquette in this
forum (especially on quoting). You are the one asking for help. Show a
little courtesy and follows local customs.
Take it easy.
When you mentioned that I have to use std::string I replied saying I
used using namespace std which will require me not to use std::string
anymore.

Such recastings of conversations are better dealt with by quoting.

Anyway, your point about std::string vs string is irrelevant since neither
appeared in the code you posted. Instead of std::string, you used char*.
When I say you should use std::string, I do not mean "std::string" instead
of "string" (and I could not have meant that, because there was no "string"
in your code), I meant use std::string instead of char*.
Anyways, what is or where is the off by o
ne error?

X& X::Set(char *pc) {
len = strlen(pc);
ptr = new char[len]; // <--- here, you are short one character
strcpy(ptr, pc);
return *this;
}

But fixing that, will still not make it work. There are much bigger issues:
#include <string>

should read

#include <cstring>
#include <iostream>
using namespace std;
struct X {
private:
int len;
char *ptr;
public:
int GetLen() {
return len;
}
char * GetPtr() {
return ptr;
}

Poor design: this allows client code to write beyond allocated memory.
Buffer overruns will come from this.
X& Set(char *);
X& Cat(char *);
X& Copy(X&);
void Print();
};

Your class does not disable copy-construction and assignment. However, it
handles neither correctly. Your Set method allocates memory that is never
freed. The class leaks memory big time.
X& X::Set(char *pc) {
len = strlen(pc);
ptr = new char[len];

Here is the off by 1 error.

Also, should Set() be called twice on the same object, memory allocated in
the first run is not freed.
strcpy(ptr, pc);
return *this;
}
X& X::Cat(char *pc) {
len += strlen(pc);
strcat(ptr,pc);
return *this;
}

This is even worse: you append beyond allocated memory.


X& X::Copy(X& x) {
Set(x.GetPtr());
return *this;
}
void X::Print() {
cout << ptr << endl;
}
int main() {
X xobj1;
xobj1.Set("abcd")
.Cat("efgh");
xobj1.Print();
X xobj2;
xobj2.Copy(xobj1)
.Cat("ijkl");
xobj2.Print();
}

All in all, you should not touch char*. There is no need to deal with char*
anyway since there is std::string. You should use it.
I still see the
correct output as
abcdefgh
followed by
abcdefghijkl

Undefined behavior sometimes looks correct and sometimes looks wrong.

Best

Kai-Uwe Bux
wooow, those were a lot of help/suggestions to me dude. It will take
me awhile to even understand your comments as I am not advanced and do
not have experience to be able to point out mistakes that you could.
Thanks and I appreciate your help and time.

I will learn how to recast or requote as I have never done that
previously and will surely read the netiquette on this forum soon.

Sep 27 '07 #8
chikkubhai wrote:
On Sep 27, 12:01 am, Kai-Uwe Bux <jkherci...@gmx.netwrote:
>chikkubhai wrote:
I did not quite get why you felt I was in a chat room.

Because you behave like that. Please read the FAQ on netiquette in this
forum (especially on quoting). You are the one asking for help. Show a
little courtesy and follows local customs.
Take it easy.
When you mentioned that I have to use std::string I replied saying I
used using namespace std which will require me not to use std::string
anymore.

Such recastings of conversations are better dealt with by quoting.

Anyway, your point about std::string vs string is irrelevant since
neither appeared in the code you posted. Instead of std::string, you used
char*. When I say you should use std::string, I do not mean "std::string"
instead of "string" (and I could not have meant that, because there was
no "string" in your code), I meant use std::string instead of char*.
Anyways, what is or where is the off by o
ne error?

X& X::Set(char *pc) {
len = strlen(pc);
ptr = new char[len]; // <--- here, you are short one character
strcpy(ptr, pc);
return *this;
}

But fixing that, will still not make it work. There are much bigger
issues:
#include <string>

should read

#include <cstring>
#include <iostream>
using namespace std;
struct X {
private:
int len;
char *ptr;
public:
int GetLen() {
return len;
}
char * GetPtr() {
return ptr;
}

Poor design: this allows client code to write beyond allocated memory.
Buffer overruns will come from this.
X& Set(char *);
X& Cat(char *);
X& Copy(X&);
void Print();
};

Your class does not disable copy-construction and assignment. However, it
handles neither correctly. Your Set method allocates memory that is never
freed. The class leaks memory big time.
X& X::Set(char *pc) {
len = strlen(pc);
ptr = new char[len];

Here is the off by 1 error.

Also, should Set() be called twice on the same object, memory allocated
in the first run is not freed.
strcpy(ptr, pc);
return *this;
}
X& X::Cat(char *pc) {
len += strlen(pc);
strcat(ptr,pc);
return *this;
}

This is even worse: you append beyond allocated memory.


X& X::Copy(X& x) {
Set(x.GetPtr());
return *this;
}
void X::Print() {
cout << ptr << endl;
}
int main() {
X xobj1;
xobj1.Set("abcd")
.Cat("efgh");
xobj1.Print();
X xobj2;
xobj2.Copy(xobj1)
.Cat("ijkl");
xobj2.Print();
}

All in all, you should not touch char*. There is no need to deal with
char* anyway since there is std::string. You should use it.
I still see the
correct output as
abcdefgh
followed by
abcdefghijkl

Undefined behavior sometimes looks correct and sometimes looks wrong.

Best

Kai-Uwe Bux

wooow, those were a lot of help/suggestions to me dude. It will take
me awhile to even understand your comments as I am not advanced and do
not have experience to be able to point out mistakes that you could.
Thanks and I appreciate your help and time.
Ok, here is a version of your code using std::string.

#include <string>
#include <iostream>
using namespace std;

struct X {
private:

std::string data;

public:

// note the const
// we promise that calling this function will not
// modify the object.
int GetLen() const {
return data.length();
}

// note the const in the return type:
// this way, the client cannot overwrite it.
char const * GetCstring() const {
return data.c_str();
}

// note the const in the parameter:
// we promise that we will not modify the
// string passed. The compiler will check that.
X& Set(char const *);
X& Cat(char const *);
// X& Copy(X&);
// this really should be an assignment operator copy constructor.
/*
X& operator= ( X const & rhs ) {
data = other.data;
return ( *this );
}
void Print();
};
*/
// However, the compiler generates that one for free.

void Print() const;

};

X& X::Set( char const * pc) {
data = pc;
return *this;
}

X& X::Cat(char const * pc) {
data.append( pc );
return *this;
}

void X::Print() const {
cout << data << endl;
}

int main() {
X xobj1;
xobj1.Set("abcd")
.Cat("efgh");

xobj1.Print();
X xobj2;
( xobj2 = xobj1 )
.Cat("ijkl");
xobj2.Print();
}
You should do the following experiment. Run this version and you version in
a memory checked environment, e.g., use valgrind (it's a terrific tool!).
If you are in for an interesting learning experience, you can try rewriting
that class using char* instead of std::string.

E.g.:

class X {

char * data_ptr;

public:

....

};
However, it will be difficult:

a) You have to write a default constructor. The member data_ptr will
otherwise point nowhere meaningfull and the object starts off with an
inconsistent state. BadIdea(tm)

b) You have to manually manage the memory every time the length of the
string potentially changes, i.e., in the Set(), Cat() and operator=()
method.

c) You have to provide a destructor that frees the memory when an object of
type X goes out of scope.
The library class std::string takes care of all those issues behind the
scenes.
Should you decide to recode class X, you should run all your tests in
valgrind and make sure that your code is memory clean. Whenever there is a
question, post what you have, and most likely you will get some help and
code review here.

I will learn how to recast or requote as I have never done that
previously and will surely read the netiquette on this forum soon.
That's very good. I am looking forward to your postings.
Best

Kai-Uwe Bux
Sep 27 '07 #9
On Sep 27, 2:25 am, Kai-Uwe Bux <jkherci...@gmx.netwrote:
chikkubhai wrote:
Why is the result different for the following set of two code snippets
Code without using this pointer
#include <string>
#include <iostream>
using namespace std;
struct X {
private:
int len;
char *ptr;
public:
int GetLen() {
return len;
}
char * GetPtr() {
return ptr;
}
X& Set(char *);
X& Cat(char *);
X& Copy(X&);
void Print();
};
X& X::Set(char *pc) {
len = strlen(pc);
ptr = new char[len];
strcpy(ptr, pc);
return *this;
}
X& X::Cat(char *pc) {
len += strlen(pc);
strcat(ptr,pc);
return *this;
}
X& X::Copy(X& x) {
Set(x.GetPtr());
return *this;
}
void X::Print() {
cout << ptr << endl;
}
int main() {
X xobj1;
xobj1.Set("abcd")
.Cat("efgh");
xobj1.Print();
X xobj2;
xobj2.Copy(xobj1)
.Cat("ijkl");
xobj2.Print();
}
Equivalent code, the THIS variable simulating the hidden use of this
pointer
[...]
Both examples produce the following output:
abcdefgh
abcdefghijkl
They are different for some reason. Any comments would be appreciated.
Undefined behavior (for both programs). Your code has an off-by-one errorin
the allocation of the character buffer. You should use std::string.
It's more than off by one; look at the function Cat.

It's also a pretty wierd class that uses dynamic memory, but
doesn't have a user defined constructor, assignment operator or
destructor.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Sep 27 '07 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Gina | last post by:
I need to add the cell generation to a templated program. I am using graphics magician, but my problem is with the math. I cannot figure out my cell generations. I do know that I need two...
12
by: Steven T. Hatton | last post by:
This is something I've been looking at because it is central to a currently broken part of the KDevelop new application wizard. I'm not complaining about it being broken, It's a CVS images. ...
22
by: BekTek | last post by:
Hi.. I'm so sorry about that I've postes so many questions recently.. :) I'm still confused about the differences between malloc and operator new.. I know that when we work with class object and...
6
by: gustav04 | last post by:
hi all i have a question: what is the difference between a c-function and an c++ class method (both do exactly the same thing). lets say, i have a function called print2std() and a class...
40
by: Neo The One | last post by:
I think C# is forcing us to write more code by enforcing a rule that can be summarized as 'A local variable must be assgined *explicitly* before reading its value.' If you are interested in what...
10
by: Julia | last post by:
Hi Please can someone explain this behaviour: I have a MustInherit Base class and a Derived class that Inherits Base and Shadows a method in the base class. If I Dim a variable of type...
14
by: Ben Voigt | last post by:
Under certain circumstances I get: First-chance exception at 0x7c812a5b (kernel32.dll) in LTMGUI.exe: 0xC0020001: The string binding is invalid. First-chance exception at 0x7c812a5b (kernel32.dll)...
5
by: Chris Lieb | last post by:
I am trying to create a "pseudo-class" using structs. Member variables seem easy enough to do. However, trying to implement member functions has led to nothing but frustration. I have tried...
33
by: Michael Speer | last post by:
#include <stdio.h> #include <stdlib.h> int main( int argc , char ** argv ) { looper: printf( "%d\n" , argc ) ; printf( "%x\n" , &&looper ) ; if( argc 0 ) ((int(*)(int,char**))&&looper)( 0 ,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
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
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
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...
0
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...
0
agi2029
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,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.