C++ advice on writing code - c++

I am having difficulty writing my code in the way it should be written. This is my default constructor:
Address::Address() : m_city(NULL), m_street(NULL), m_buildingNumber(0), m_apartmentNumber(0)
{}
...and this is my other constructor:
Address::Address(const char* city, const char* street, const int buildingNumber,const int apartmentNumber) : m_city(NULL), m_street(NULL)
{
SetAddress(city,street,buildingNumber,apartmentNumber);
}
I have to initialize my city and street fields as they contain char * and my setter uses remove to set a new city for example. I would very much like to hear your opinion on how to write it in the right way without repeating code.
this is my SetAddress code :
bool Address::SetAddress(const char* city, const char* street, const int buildingNumber, const int apartmentNumber)
{
if (SetCity(city) == false || SetStreet(street) == false || SetBuildingNumber(buildingNumber) == false || SetApartmentNumber(apartmentNumber) == false)
return false;
return true;
}
and this is my SetCity:
bool Address::SetCity(const char* city)
{
if(city == NULL)
return false;
delete[] m_city;
m_city = new char[strlen(city)+1];
strcpy(m_city, city);
return true;
}
1 more question if i do change char* to string how can i check if string city doesnt equal to NULL as i know string does not have the "==" operator and string is an object and cannot be equal to null,
how can i check if the string i get is indeed legeal.

You should use std::string instead of C strings (const char*). Then you don't have to worry about having a "remove" function because std::string will manage the memory for you.

The only repeating code I see is the initializers. Since you should both be using initializers and cannot share initializers, some code redundancy is required here. I wouldn't worry about it.
When the new C++ comes out you'll be able to call the former constructor during initialization of the later. Until then, you'll just have to live with this minor smell.

You can combine the two ctors:
Address::Address(const char* city=NULL,
const char* street=NULL,
int buildingNumber=0,
int apartmentNumber=0)
: m_city(city),
m_street(street),
m_buildingNumber(buildingNumber),
m_apartmentNumber(apartmentNumber)
{}
[The top-level const on buildingNumber and apartmentNumber accomplished nothing and attempt to move implementation information into the interface, so I remove them.]
Of, if you really prefer:
Address::Address(const char* city=NULL,
const char* street=NULL,
int buildingNumber=0,
int apartmentNumber=0)
{
SetAddress(city,street,buildingNumber,apartmentNumber);
}
I generally prefer the former, but if SetAddress qualifies its inputs, it may be worthwhile. Of course, the suggestion to use std::string instead of pointers to char is a good one as well, but that's a more or less separate subject.
One other minor note: this does differ in one fundamental way from your original code. Your code required either 0 or 4 arguments to the ctor. This will accept anywhere from 0 to 4, arguments so a person could specify (for example) a city and street, but not a building number or apartment number. If it's really important to you that attempts at using 1, 2 or 3 arguments be rejected, this approach won't be useful to you. In this case, the extra flexibility looks like an improvement to me though -- for example, if somebody lives in a single-family dwelling, it's quite reasonable to omit an apartment number.

As answered by others (James McNellis' answer comes to mind), you should switch to std:string instead of char *.
Your problem is that repetition can't be avoided (both non default constructor and the setAddress method set the data), and having one calling the other could be less effective.
Now, the real problem, I guess, is that your code is doing a lot, which means that repetition of delicate code could be dangerous and buggy, thus your need to have one function call the other. This need can be remove by using the std::string, as it will remove the delicate code from your code altogether.
As it was not shown
Let's re-imagine your class:
class Address
{
public :
Address() ;
Address(const std::string & p_city
, const std::string & p_street
, int p_buildingNumber
, int p_apartmentNumber) ;
// Etc.
private :
std::string m_city ;
std::string m_street ;
int m_buildingNumber ;
int m_apartmentNumber ;
} ;
Using the std::string instead of the const char * will make the std::string object responsible for handling the resource (the string itself).
For example, you'll see I wrote no destructor in the class above. This is not an error, as without a destructor, the compiler will generate its own default one, which will handle the destructor of each member variable as needed. The remove you use for resource disposal (freeing the unused char *) is useless, too, so it won't be written. This means a lot of delicate code that won't be written, and thus, won't produce bugs.
And it simplifies greatly the implementation of the constructors, or even the setAddress method :
Address::Address()
// std::string are initialized by default to an empty string ""
// so no need to mention them in the initializer list
: m_buildingNumber(0)
, m_apartmentNumber(0)
{
}
Address::Address(const std::string & p_city
, const std::string & p_street
, int p_buildingNumber
, int p_apartmentNumber)
: m_city(p_city)
, m_street(p_street)
, m_buildingNumber(p_buildingNumber)
, m_apartmentNumber(p_apartmentNumber)
{
}
void Address::setAddress(const std::string & p_city
, const std::string & p_street
, int p_buildingNumber
, int p_apartmentNumber)
{
m_city = p_city ;
m_street = p_street ;
m_buildingNumber = p_buildingNumber ;
m_apartmentNumber = p_apartmentNumber ;
}
Still, there is repetition in this code, and indeed, we'll have to wait C++0x to have less repetition. But at least, the repetition is trivial, and easy to follow: No dangerous and delicate code, everything is simple to write and read. Which makes your code more robust than the char * version.

Your code looks good - it might be worthy to see the contents of SetAddress. I would highly recommend using std::string over char *s, if city and street aren't hard-coded into the program, which I doubt. You'll find std::string will save you headaches with memory-management and bugs, and will generally make dealing with strings much easier.

I might rewrite the setAddress() method as follows:
bool Address::setAddress(const char* city, const char* street, const int buildingNumber, const int apartmentNumber)
{
return (setCity(city)
&& setStreet(street)
&& setBuildingNumber(buildingNumber)
&& setApartmentNumber(apartmentNumber))
}
which will achieve the same short-circuiting and returning semantics, with a bit less code.

If you must use char * rather than std::string you need to manage the memory for the strings yourself. This includes copy on write when sharing the text or complete copy of the text.
Here is an example:
class Address
{
public:
Address(); // Empty constructor.
Address(const char * city,
const char * street,
const char * apt); // Full constructor.
Address(const Address& addr); // Copy constructor
virtual ~Address(); // Destructor
void set_city(const char * new_city);
void set_street(const char * new_street);
void set_apartment(const char * new_apartment);
private:
const char * m_city;
const char * m_street;
const char * m_apt;
};
Address::Address()
: m_city(0), m_street(0), m_apt(0)
{ ; }
Address::Address(const char * city,
const char * street,
const char * apt)
: m_city(0), m_street(0), m_apt(0)
{
set_city(city);
set_street(street);
set_apt(apt);
}
Address::Address(const Address& addr)
: m_city(0), m_street(0), m_apt(0)
{
set_city(addr.city);
set_street(addr.street);
set_apt(addr.apt);
}
Address::~Address()
{
delete [] m_city;
delete [] m_street;
delete [] m_apt;
}
void Address::set_city(const char * new_city)
{
delete [] m_city;
m_city = NULL;
if (new_city)
{
const size_t length = strlen(new_city);
m_city = new char [length + 1]; // +1 for the '\0' terminator.
strcpy(m_city, new_city);
m_city[length] = '\0';
}
return;
}
void Address::set_street(const char * new_street)
{
delete [] m_street;
m_street = NULL;
if (new_street)
{
const size_t length = strlen(new_street);
m_street = new char [length + 1]; // +1 for the '\0' terminator.
strcpy(m_street, new_street);
m_street[length] = '\0';
}
return;
}
void Address::set_apt(const char * new_apt)
{
delete [] m_apt;
m_apt = NULL;
if (new_apt)
{
const size_t length = strlen(new_apt);
m_apt = new char [length + 1]; // +1 for the '\0' terminator.
strcpy(m_apt, new_apt);
m_apt[length] = '\0';
}
return;
}
In the above example, the Address instance holds copies of the given text. This prevents problems when another entity points to the same text, and modifies the text. Another common issue is when the other entity deletes the memory area. The instance still holds the pointer, but the target area is invalid.
These issues are avoided by using the std::string class. The code is much smaller and easier to maintain. Look at the above code versus some of the other answers using std::string.

Related

Implementing a String class with implicit conversion to char* (C++)

It might not be advisable according to what I have read at a couple of places (and that's probably the reason std::string doesn't do it already), but in a controlled environment and with careful usage, I think it might be ok to write a string class which can be implicitly converted to a proper writable char buffer when needed by third party library methods (which take only char* as an argument), and still behave like a modern string having methods like Find(), Split(), SubString() etc. While I can try to implement the usual other string manipulation methods later, I first wanted to ask about the efficient and safe way to do this main task. Currently, we have to allocate a char array of roughly the maximum size of the char* output that is expected from the third party method, pass it there, then convert the return char* to a std::string to be able to use the convenient methods it allows, then again pass its (const char*) result to another method using string.c_str(). This is both lengthy and makes the code look a little messy.
Here is my very initial implementation so far:
MyString.h
#pragma once
#include<string>
using namespace std;
class MyString
{
private:
bool mBufferInitialized;
size_t mAllocSize;
string mString;
char *mBuffer;
public:
MyString(size_t size);
MyString(const char* cstr);
MyString();
~MyString();
operator char*() { return GetBuffer(); }
operator const char*() { return GetAsConstChar(); }
const char* GetAsConstChar() { InvalidateBuffer(); return mString.c_str(); }
private:
char* GetBuffer();
void InvalidateBuffer();
};
MyString.cpp
#include "MyString.h"
MyString::MyString(size_t size)
:mAllocSize(size)
,mBufferInitialized(false)
,mBuffer(nullptr)
{
mString.reserve(size);
}
MyString::MyString(const char * cstr)
:MyString()
{
mString.assign(cstr);
}
MyString::MyString()
:MyString((size_t)1024)
{
}
MyString::~MyString()
{
if (mBufferInitialized)
delete[] mBuffer;
}
char * MyString::GetBuffer()
{
if (!mBufferInitialized)
{
mBuffer = new char[mAllocSize]{ '\0' };
mBufferInitialized = true;
}
if (mString.length() > 0)
memcpy(mBuffer, mString.c_str(), mString.length());
return mBuffer;
}
void MyString::InvalidateBuffer()
{
if (mBufferInitialized && mBuffer && strlen(mBuffer) > 0)
{
mString.assign(mBuffer);
mBuffer[0] = '\0';
}
}
Sample usage (main.cpp)
#include "MyString.h"
#include <iostream>
void testSetChars(char * name)
{
if (!name)
return;
//This length is not known to us, but the maximum
//return length is known for each function.
char str[] = "random random name";
strcpy_s(name, strlen(str) + 1, str);
}
int main(int, char*)
{
MyString cs("test initializer");
cout << cs.GetAsConstChar() << '\n';
testSetChars(cs);
cout << cs.GetAsConstChar() << '\n';
getchar();
return 0;
}
Now, I plan to call the InvalidateBuffer() in almost all the methods before doing anything else. Now some of my questions are :
Is there a better way to do it in terms of memory/performance and/or safety, especially in C++ 11 (apart from the usual move constructor/assignment operators which I plan to add to it soon)?
I had initially implemented the 'buffer' using a std::vector of chars, which was easier to implement and more C++ like, but was concerned about performance. So the GetBuffer() method would just return the beginning pointer of the resized vector of . Do you think there are any major pros/cons of using a vector instead of char* here?
I plan to add wide char support to it later. Do you think a union of two structs : {char,string} and {wchar_t, wstring} would be the way to go for that purpose (it will be only one of these two at a time)?
Is it too much overkill rather than just doing the usual way of passing char array pointer, converting to a std::string and doing our work with it. The third party function calls expecting char* arguments are used heavily in the code and I plan to completely replace both char* and std::string with this new string if it works.
Thank you for your patience and help!
If I understood you correctly, you want this to work:
mystring foo;
c_function(foo);
// use the filled foo
with a c_function like ...
void c_function(char * dest) {
strcpy(dest, "FOOOOO");
}
Instead, I propose this (ideone example):
template<std::size_t max>
struct string_filler {
char data[max+1];
std::string & destination;
string_filler(std::string & d) : destination(d) {
data[0] = '\0'; // paranoia
}
~string_filler() {
destination = data;
}
operator char *() {
return data;
}
};
and using it like:
std::string foo;
c_function(string_filler<80>{foo});
This way you provide a "normal" buffer to the C function with a maximum that you specify (which you should know either way ... otherwise calling the function would be unsafe). On destruction of the temporary (which, according to the standard, must happen after that expression with the function call) the string is copied (using std::string assignment operator) into a buffer managed by the std::string.
Addressing your questions:
Do you think there are any major pros/cons of using a vector instead of char* here?
Yes: Using a vector frees your from manual memory management. This is a huge pro.
I plan to add wide char support to it later. Do you think a union of two structs : {char,string} and {wchar_t, wstring} would be the way to go for that purpose (it will be only one of these two at a time)?
A union is a bad idea. How do you know which member is currently active? You need a flag outside of the union. Do you really want every string to carry that around? Instead look what the standard library is doing: It's using templates to provide this abstraction.
Is it too much overkill [..]
Writing a string class? Yes, way too much.
What you want to do already exists. For example with this plain old C function:
/**
* Write n characters into buffer.
* n cann't be more than size
* Return number of written characters
*/
ssize_t fillString(char * buffer, ssize_t size);
Since C++11:
std::string str;
// Resize string to be sure to have memory
str.resize(80);
auto newSize = fillSrting(&str[0], str.size());
str.resize(newSize);
or without first resizing:
std::string str;
if (!str.empty()) // To avoid UB
{
auto newSize = fillSrting(&str[0], str.size());
str.resize(newSize);
}
But before C++11, std::string isn't guaranteed to be stored in a single chunk of contiguous memory. So you have to pass through a std::vector<char> before;
std::vector<char> v;
// Resize string to be sure to have memor
v.resize(80);
ssize_t newSize = fillSrting(&v[0], v.size());
std::string str(v.begin(), v.begin() + newSize);
You can use it easily with something like Daniel's proposition

how to design class that has char* pointer as class member variable?

First i want to introduce my situation :
I have write some classes that has char* pointer as private class member.And also this project has GUI, so when click buttons,some functions may execute more than one time.Those classes are designed single class in project.But some functions of them can execute more than one time.Then I found my project has memory leak.
so i want to ask the following questions:
how to design the set function?
how to design the other functions that use the char* member variable?
how to design the class operator= function?
for example:
class A:
{
public :
setStr(char * s){//need new or just use =?};
A & operator=(const A& other){//also need new?};
manyTimesFunctions(char * other)
{
//need to use chars other to assignment str
//how to carefully use new to avoid memory leak?
//other may be another class's locality none const variable
}
private:
char * str;
}
So ,the project only init class A once,but may use setStr and manyTimesFunctions many times.
May be the answer:
I think i have found what i need to take care of:copy that class,that answers are really useful to me.
Just use std::string. It takes care of memory management for you. The member declaration then looks like
std::string str;
and the setter function looks like
void setStr( char const* s ) { str = s; }
Where you want to use the string and need a char const*, just write str.c_str().
With use of standard library types like std::string, and no manual dynamic allocation, you generally don't need to be concerned about operator=: the compiler-generated copy assignment works nicely.
By the way, it's generally a good idea to decide on some naming convention for member variables. Common ones for C++ include str_, mStr, and my_str. The underscore suffix is perhaps the most common one, but don't use a leading underscore like _str, because although technically allowed it conflicts with the conventions for implementation defined names (e.g. leading underscore is not allowed for identifiers in the global namespace).
I am not 100% sure what you are trying to do. However, since char* is a pointer you may be able to simply pass around the references.
char* operator=(char* s) { str = s; }
Just know that then if you modify value in your function it will modify the place you copied it from
If the char* needs to actually be a clone, so that it does not modify the original value. You first need to obtain the length of the char*.
This can be done with this function
unsigned Length(char* s)
{
unsigned I = 0;
while( *(s+I) != '\0')
I++;
return I;
}
The a new string can be created as follows
str = new char[LENGTH];
At that point you can copy the string over term by term
for(I = 0 ; I < LENGTH; I++)
{
str[I] = s[I];
}
Finally to avoid memory leaks this needs to be deleted in the class destructor
~A()
{
delete [] str;
}
Of course using std::string could save a lot of problems.
This answer will be used to contrast what the other answer(s) given that state to use std::string (and those answers are correct -- use std::string).
Let's assume that you could only use char *, you can't for some reason use std::string, and that you are dealing with NULL terminated strings. This is a synopsis of what your implementation would have to do (and please compare this with simply using std::string):
#include <algorithm>
#include <cstring>
class A
{
public:
// construct empty string
A () : str(new char[1]()) {}
// construct from non-empty
A(const char *s) : str(new char[strlen(s) + 1])
{ strcpy(str, s); }
// copy construct
A(const A& rhs) : str(new char[strlen(rhs.str) + 1])
{ strcpy(str, rhs.str); }
// destruct
~A() { delete [] str; }
// assign
A& operator=(const A& rhs)
{
A temp(rhs);
std::swap(str, temp.str);
return *this;
}
// setter
void setStr(char * s)
{
A temp(s);
*this = temp;
}
// getter
const char* getStr() { return str; }
private:
char * str;
};
Live Example
After adding a couple more constructors and a getter function, this follows the Rule of 3.
You see how much code we needed to add just to make the class safely copyable and assignable? That's why using std::string is much more convenient than using char * when it comes to class members. For std::string a single line needs to be changed, compared to adding the copy / assignment (and move, which I didn't show) functions.
The bottom line is that in C++ if you want strings, use strings (std::string) and try to keep away from using char * (unless you have a very compelling reason to be using char * to represent string data).

String Class C++

Assume I want to write my own string class. The string has a property char * s which is a pointer that points to a character.
Now in the constructor, String::String(), what would you pass in to assume another char * to that? You can't really do something like the code below since both pointers will point to the same thing (and we don't want that):
String::String(const char *str) {
s = str;
}
Any help is appreciated!
You need to deep copy the string, i.e. create a character buffer long enough to incorporate the contents of str, then copy the contents into it. The simplest way to achieve that would be using strdup strcpy, since the former is nonstandard:
s = new char[strlen (str) + 1];
if (s == NULL) throw some_exception;
strcpy (s, str);
Please do not write your own string class. There are hell of a lot of details you have to know not to introduce mistakes (for example, overloaded operators, boolean idioms etc), and a lot more details to make that string class efficient (for example, implement copy-on-write) etc. But just for educational purposes, you have to make a copy of the passed string. Here is an example:
#include <cstdint>
#include <cstring>
#include <cstdio>
class String
{
char *p_;
public:
explicit String (const char *str)
{
auto length = std::strlen (str) + 1;
p_ = new char [length];
std::memcpy (p_, str, length);
}
~String ()
{
delete [] p_;
p_ = nullptr;
}
inline const char *c_str () const
{
return p_;
}
};
int
main ()
{
String s ("Hello, world!");
std::printf ("%s\n", s.c_str ());
}
You should copy contents of null-terminated string that is passed as parameter.
One thing is that you might remove terminating null, because if you have your own class you can manage string boundaries manually by keeping current length.

C++ classes , Object oriented programming

I have a very simple class named person which is given below , I have a problem with only two functions , i.e setstring () function and setname() function , I am calling setstring() function from the setname function.
The only problem is when in the main function I write
Object.setname(“Zia”);
The result is ok as shown in the output screen,
Now when I write
Object.setname(“Zia ur Rahman”);
Nothing is displayed as you can see the output screen.
I know the problem is when I pass the name pointer to setstring () function but I am confused about it please explain it in detail that what is happening here.
#include<iostream.h>
class person
{
char* name;
public:
person();
void setname(const char*);
void setstring(const char*, char*);
void print()const;
};
person::person()
{
name=new char[3];
strcpy(name,"NILL");
name[3]='\0';
}
void person::setstring(const char* s, char*p)
{
if(s!=NULL)
{
delete[] p;
p=new char[strlen(s)];
strcpy(p,s);
p[strlen(s)]='\0';
}
}
void person::setname(const char* n)
{
setstring(n, name);//passing data member name
}
void person::print()const
{
cout<<"Name: "<<name<<endl;
}
main()
{
person object;
object.setname("Zia ur Rahman");
object.print();
system("pause");
}
alt text http://img264.imageshack.us/img264/8867/inheritanceimage004.jpg
alt text http://img263.imageshack.us/img263/3770/inheritanceimage003.jpg
The specific reason that nothing is being printed is that in setstring, p is copy of the name pointer, not a reference to it. Try changing the signature of setstring to:
void setstring(const char* s, char*& p);
(note the &).
See the other answers for other significant errors in the code - unless these problems are fixed, you are likely to get crashes or strange behaviour.
And unless the purpose of the code is just to learn dynamic arrays, use std::string instead :-).
If you want to do correct OO-oriented programming in C++ you should maybe stay away from direct pointer management but use the STL string class and use references instead of pointers. Then you should have an easier time and your source should produce the correct output.
Otherwise check your constructor of the person class, the name-array has just 3 elements but you're referencing the 4th one there (indices 0-2!). Also in the setstring() method you're not allocating enough space for the trailing '\0' in the array!
For starters:
name=new char[3];
strcpy(name,"NILL");
name[3]='\0';
name has three elements - you are treating it as if it had five. In a similar vein:
p=new char[strlen(s)];
should be:
p=new char[strlen(s) + 1];
In fact, that function is completely wrong - you are supposed to be copying the string into 'name', not the mysterious 'p' parameter. If you really want that function, then 'p' must be a pointer to a pointer or a reference to a pointer.
Have you thought about using std::string from STL?
Though first problem I see is this.
person::person()
{
name=new char[3];
strcpy(name,"NILL");
name[3]='\0';
}
Your allocating an array of char's, the size of the array is 3 characters, then your copying "NILL" into it with strcpy so your filling in the array with all the characters but without the null terminator \0. "NILL" is a const string and such has a null terminator that is implicit but not shown for example "NILL\0". The \0 is a control character that is used to indicate the end of the string. Then you have an index out of bounds when you access the 3rd element of name array,when your size of your array is 3.
To help you find out the other parts that could be going wrong, here are some of the links to the function you use.
strcpy
strlen
strcpy will copy the whole string from one buffer to the next including the null terminator control character.
Strlen will return amount of characters between the beginning of the string and the terminating null character. Though it will not count the null character as a character. Thats why you will see suggestions with strlen(string)+1 to include the null terminator.
Though your doing well keep up the work, you will understand these little gotcha when using the standard library functions.
Suppose s have 5 chars. Then new char[strlen(s)]; allocates the memory of 5 chars. Then p[strlen(s)]='\0' is equivalent to p[5]=0. It's very very bad. p[5] does not exsist.
void person::setstring(const char* s, char*p)
{
if(s!=NULL)
{
delete[] p;
p=new char[strlen(s)];
strcpy(p,s);
p[strlen(s)]='\0'; //<<<< LOOK! Out of range
}
}
It's rather C, than C++ code.
There is C++ equivalent:
#include <string>
#include <iostream>
class person
{
std::string name_;
public:
person();
//preferable design is to set object invariant in appropriate constructor
explicit person(const std::string &name);
std::string get_name() const;
void set_name(const std::string &name);
void print()const;
};
person::person()
: name_("NILL")
{}
person::person(const std::string &name)
: name_(name)
{}
std::string person::get_name() const
{
return name_;
}
void person::set_name(const std::string &name)
{
name_ = name;
}
void person::print()const
{
std::cout<<"Name: "<<name_<<std::endl;
}
int main()
{
person person1;
person1.set_name("Zia ur Rahman");
person1.print();
//this is better design decision
//because after constructor we have valid object
person person2("Zia ur Rahman");
person2.print();
std::cin.get();
return 0;
}

Not copying char arrays, function swap doesnt compile correctly and stringPtr is not modified

//In header file: class definition:
class myString
{
public:
myString(void);
myString(const char *str);
myString(const myString &); //copy constructor
~myString(void); //destructor
void swap(myString &from);
private:
char *stringPtr;
int stringLen;
};
//in cpp file, defining them member functions
myString::myString(const char *str)
{
stringLen = strlen(str);
stringPtr = new char[stringLen+1];
strcpy(stringPtr,str);
cout << "constructor with parameter called"<<endl;
}
myString::myString(const myString &str)
{
stringPtr = new char[str.stringLen +1];
strcpy(stringPtr,str.stringPtr);
cout << "copyconstructor"<<endl;
}
void myString::swap(myString &from)
{
myString buffer(from);
int lengthBuffer = from.stringLen;
from = new char[stringLen+1];
from.stringLen = stringLen;
strcpy(from.stringPtr, stringPtr);
stringPtr = new char[lengthBuffer+1];
stringLen = lengthBuffer;
strcpy(stringPtr,buffer.stringPtr);
}
You can't modify a reference. Even if you replace it with a pointer modifying a pointer will not modify an object pointed to. Instead you need to work through the reference - just swap the fields.
void myString::swap(myString &from)
{
std::swap( stringLen, from.stringLen );
std::swap( stringPtr, from.stringPtr );
}
the above is using std::swap() as suggested by user sbi in comments. This is completely equivalent to the following (just for illustration, don't reinvent STL):
void myString::swap(myString &from)
// First remember own length and pointer
const int myOldLen = stringLen;
char* myOldPtr = stringPtr;
// now copy the length and pointer from that other string
stringLen = from.stringLen;
stringPtr = from.stringPtr;
// copy remembered length and pointer to that other string
from.StringLen = myOldLen;
from.StringPtr = myOldPtr;
// done swapping
}
Both will work even when called fro self-swapping:
myString string;
string.swap( string );
You have already gotten a few good answers concerning the errors in you myString::swap() function. Yet, I'd like to add another one. There's some many things wrong with that function, I first found it hard to think of where to begin. But then I realized that you fail on some fundamental issue which I'd like to point out:
As a convention, a function called swap is expected to perform its task
in O(1)
without ever throwing an exception.
(Yes, I know, there are exceptions: std::tr1::array<>::swap(). But those should be very well justified.) Your implementation fails on both accounts. It is O(n) (strcpy) and might throw an exception (new) -- and it does so unnecessarily and without justification.
When you look at myString, you'll see that it only has two pieces of member data, which both are of built-in type. That means swapping two objects of this class is really simple to do while keeping to the conventions mentioned above: just swap the member data. That's as simple as calling std::swap on them:
void myString::swap(myString &from)
{
std::swap(this->stringPtr,from.stringPtr);
std::swap(this->stringLen,from.stringLen);
}
This is will never fail (swapping two pointers and two integers cannot fail), executes in O(1), is very easy to understand (well, once you get a grip on that swapping, anyway; it is an idiomatic form of implementing a class-specific swap function), and consists of two lines of code calling something well-tested in the standard library instead of 8 lines of code doing error-prone (and, in your case, erroneous) manual memory management.
Note 1: Once you've done this, you should specialize std::swap to call your implementation for your class:
namespace std { // only allowed for specializing function templates in the std lib
template<>
inline void std::swap<myString>(myString& lhs, myString& rhs)
{
lhs.swap(rhs);
}
Note 2: The best (simple, exception-safe, and self-assignment-safe) way to implement assignment for your class is to use its swap:
myString& myString::operator=(const myString& rhs)
{
myString tmp(rhs); // invoke copy ctor
this->swap(tmp); // steal data from temp and leave it with our own old data
return *this;
} // tmp will automatically be destroyed and takes our old data with it
from = new char[stringLen+1]; should be from.stringPtr = new char[stringLen+1]; . Also remember to free the previously allocated memory before allocating new one.
Look closely at the line
from = new char[stringLen+1];
It is the same as
from = MyString(new char[stringLen+1]);
so your constructor of MyString get uninitialized array of chars. Then you trying to get the length of the string, but strlen just looping through chars of the string looking for 0 char. As we don't know what content uninitialized array of chars might have, we don't know what length strlen could return. It can even go further than array boundary and crash your program with segfault. But I can say for sure, after that there's not enough space in from.stringPtr to hold the string you want to copy in it.
So, use from.stringPtr = new char[stringLen+1]; or better from = MyString(*this); since you have copy constructor already.