I am maintaining the rule of three like this --
// actual constructor
stuff::stuff(const string &s)
{
this->s_val = s[0];
this->e_val = s[s.length() - 1];
}
// copy constructor
stuff::stuff(const stuff &other)
{
this->s_val = other.s_val ;
this->e_val = other.e_val ;
}
// assignment
stuff& stuff::operator=(const stuff &other)
{
stuff temp(other);
*this = move(temp);
return *this;
}
now I can call like this --
stuff s1("abc");
stuff s2(s1);
stuff s3 = s2 ; // etc ...
Now I am trying to implement a function that will use operator= so that I can call like --
stuff s;
s = "bcd" ;
and I am writing like this --
stuff& stuff::operator=(const string &s)
{
stuff temp(s);
*this = move(temp);
return *this;
}
but it is giving me segfault. Moreover what should I do if want to call like
stuff s = "bcd" ?
how do I do that ?
you assignment operator and copy constructor should look the same :
stuff& stuff::operator=(const stuff &other)
{
this->s_val = other.s_val ;
this->e_val = other.e_val ;
return *this;
}
you can't define you = operator with another = operator .
remember, std::move doesn't do any special magic, it just turns a variable into somthing that can be cought using move semantics. you still need to define your function as one who deals with r-value-reference in the first place, which you didn't (you dont have any move assignment operator).
in you string-accepting = operator , you can use the regular one :
stuff& stuff::operator=(const string &s)
{
*this = stuff(s);
return *this;
}
few more suggestions :
your this-> is redundent. the compiler knows the variable you're refering is part of this.
also , the lines:
this->s_val = s[0];
this->e_val = s[s.length() - 1];
can be written more elegantly as:
s_val = s.first();
e_val = s.back();
btw. the copy ctor., assignemt operator and the destructor are redundent also.
the rule of three (or five, as C++11) says *IF* you implement any of the copy ctor. assigment operator or the destructor - you need to implement them all.
the question is, should you implement any of them at the first place? you don't have any dynamic allocation here, no shallow copying, and nothing special that needs special member functions (copy ctor. etc.).
you might as well delete the whole three and that will be the best case in your example.
Related
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).
I'm working on operator overloading for a self made dynamic array class. I'm also trying to learn how to use the *this pointer but it's not going so well. Below are the parts of the class and my code that I thought were needed to explain the issue.
I don't understand why I can't call a member function on the *this pointer when the *this pointer is pointing to the left side of the + equation.
Here is the stub driver that is calling the + operator:
<< and >> are already overloaded and working.
cout << "Please enter a word to add:";
string theWord;
cin >> theWord;
//add word
array1 = array1 + theWord;
cout << "array1: " << array1 << endl;
Here is the main code:
class DynamicArray
{
public:
//constructor
DynamicArray(int initialcapacity = 10);
//copy constructor
DynamicArray(const DynamicArray& rhs);
//destructor
~DynamicArray();
//operator+ - add a string
DynamicArray operator+(const string& rhs) const;
//operator+ - concatenate another DynamicArray
DynamicArray operator+(const DynamicArray& rhs) const;
//change the capacity of the DynamicArray to the newCapacity -
// may reduce the size of the array - entries past newCapacity will be lost
void resize(int newCapacity);
private:
string* mWords;//pointer to dynamic array of strings
int mNumWords;//the current number of words being kept in the dynamic array
int mCapacity;//the current capacity of the dynamic array (how many strings could fit in the array)
//display all the contained strings (each on a newline) to the output stream provided
void displayContents(ostream& output) const;
//add all the strings contained in the input stream to the dynamic array - resize if necessary
//return how many words are added to the array
int addWords(ifstream &input);
//add a single word to the dynamic array - resize if necessary
void addWord(const string& word);
};
//add a single word to the dynamic array - resize if necessary
void DynamicArray::addWord(const string& word)
{
if (mNumWords >= mCapacity)//need more space?
{
resize(mCapacity + 1);
}
mWords[mNumWords] = word;
mNumWords++;
}
This is the function I'm currently working on
//operator+ - add a string
DynamicArray DynamicArray::operator+(const string& rhs) const
{
//this doesn't work, why doesn't it, how should/do I use the
//this pointer properly
this.addWord(rhs);
return *this;
}
In addition to using this. instead of this->, you have defined operator+ as a const member function. This means that no members can be mutated, and no calls to non-const member function functions are to be performed. Your addword function is non-const. That's the reason for the error -- you are violating const correctness.
Also, why are you mutating the array for merely calling operator + in your code? That operator shouldn't need to change any aspect of the current object. I can understand operator += mutating the object, but not operator +.
What you should do is write an operator += first. This operator can mutate the current object, since that is the semantics of += (change the current object). Then operator + can be written this way:
//operator+ - add a string
DynamicArray DynamicArray::operator+(const string& rhs) const
{
DynamicArray temp = *this;
temp += rhs;
return temp;
}
This is assuming you have a working copy constructor. In the example above, you are mutating a temporary, calling += on the temporary, and returning the temporary. The this object does not change.
Here is what your operator += should look like:
DynamicArray& DynamicArray::operator+=(const string& rhs)
{
this.addWord(rhs);
return *this;
}
Now operator += becomes non-const because the intention of += is to change the current object. Note that the return value is a reference to the current object. This now works in concert with the operator + above.
Your operator+ has to be non-const since you want to change the state of the object on each it is invoked. Also you don't have to write
this->addWord( rhs); // correct but not needed
because use of method inside a class member function is called on this pointer implicitly. Given this, you may write:
DynamicArray DynamicArray::operator+(const string& rhs)
{
addWord( rhs);
return *this;
}
You can also implement this operator as void:
void DynamicArray::operator+(const string& rhs)
{
addWord( rhs);
}
and use it this way:
array1 + theWord;
I have a question about the following code:
let's say I have a class P that has a copy constructor and a regular constructor the receives one string value.
I have the following code:
P doSomething(){
P p("myValue");
return p;
}
int main(){
P m=doSomething();
return 1;
}
why isn't copy constructor invoked at the return p of the doSomething() function?
the call P m=doSomething() - does it suppose to call the copy constructor or the operator=?
in case it's operator =, what is the difference of this code and the following:
P new_val=("newVal");
p m=new_val;
(i know here the call is for copy constructor)
Thanks,
Mary
why isn't copy constructor invoked at the return p of the doSomething() function?
The standard allows this copy to be elided. Google for [N]RVO. On certain compilers this happens only when optimizing, on others it is part of the calling conventions and thus happens always.
the call P m=doSomething() - does it suppose to call the copy constructor or the operator=?
T t = x; is "syntactic sugar" (in the sense that the T(x) is happening implicitly) for T t(T(x)) and thus has -- despite the = -- nothing to do with operator=. Note that also here the additional temporary may be elided, thus no copy ctor is called.
in case it's operator =, what is the difference of this code and the following:
This code makes no sense, what did you really mean?
P new=("newVal");
p m=new;
I made a small sample for demonstration.
void print(char* text, int ident)
{
for(int i = 0 ; i < ident ; i++)
{
printf(" ");
} // end for
fprintf(stdout, text);
fprintf(stdout, "\n");
fflush(stdout);
}
class P
{
public:
char* _str;
P (P& arg)
{
print("copy constructor", 2);
arg._str = this->_str;
}
P (char* str)
{
print("constructor", 2);
_str = str;
}
};
P doSomething(){
print("do something - function", 1);
P p("myValue");
print("before return p", 1);
return p;
}
int main(int argc, char* argv[])
{
print("start", 0);
P m=doSomething();
print("stop - call return", 0);
return 1;
}
this returns
start
do something - function
constructor
before return p
copy constructor
stop - call return
so copy constructor WILL BE CALLED
1) why isn't copy constructor invoked at the "return p" of the doSomething() function?
it should - try printing something to the console in the copy c-tor to see if it is really running.
2) the call P m=doSomething() - does it suppose to call the copy constructor or the operator=?
should call the operator=. again, use the debug message print from within the method to check
3) in case it's operator =, what is the difference of this code and the following:
P new=("newVal"); p m=new; (i know here the call is for copy constructor)
did you miss something on the code snippet? i think it won't compile
This is a homework assignment. The Field container was the assignment from a week ago, and now I'm supposed to use the Field container to act as a dynamic array for a struct NumPair which holds two char * like so:
struct NumPair
{
char *pFirst, *pSecond;
int count;
NumPair( char *pfirst = "", char *psecond = "", int count = 0)
: pFirst(strdup(pfirst)), pSecond(strdup(psecond)), count(count)
{ }
NumPair( const NumPair& np )
: count(np.count), pFirst(strdup(np.pFirst)), pSecond(strdup(np.pSecond))
{ }
NumPair& operator=( const NumPair& np )
{
if(this != &np)
{
pFirst = strdup(np.pFirst);
pSecond = strdup(np.pSecond);
count = np.count;
}
return *this;
}
and the Field container
Field<NumPair> dict_;
The homework requires the use of char *, and not string, so that we can get better with all this low-level stuff. I've already had some question about char to wchar_t conversions, etc.
Now I have a question as to whether or not I'm destructing the NumPair properly. The scenario is as follows:
1) Field destructor gets called
template <class T>
Field<T>::~Field()
{
delete[] v_;
}
2) Delete calls the destructor of every element NumPair in v_;
~NumPair()
{
free(pFirst);
free(pSecond);
}
Is this okay? I haven't really read too many articles about mixing and matching elements created on the heap and free-store as we wish. I figure as long as I don't use delete on an improper malloc'ed element, I should be fine.
However, I don't know the entire intricacies of the delete command, so I'm wondering whether or not this is valid design, and what I could do to make it better.
Also, of course this isn't. I'm getting an error of the type:
This may be due to a corruption of the heap and points to dbgheap
extern "C" _CRTIMP int __cdecl _CrtIsValidHeapPointer(
const void * pUserData
)
{
if (!pUserData)
return FALSE;
if (!_CrtIsValidPointer(pHdr(pUserData), sizeof(_CrtMemBlockHeader), FALSE))
return FALSE;
return HeapValidate( _crtheap, 0, pHdr(pUserData) ); // Here
}
Again, how could I improve this without the use of string?
FIELD CTOR/Copy Ctor/Assignment
template <class T>
Field<T>::Field()
: v_(0), vused_(0), vsize_(0)
{ }
template <class T>
Field<T>::Field(size_t n, const T &val)
: v_(0), vused_(n), vsize_(0)
{
if(n > 0)
{
vsize_ = 1;
while(vsize_ < n)
vsize_ <<= 1;
v_ = new T[vsize_];
std::fill(v_, (v_ + vused_), val);
}
}
template <class T>
Field<T>::Field(const Field<T> &other)
: v_(new T[other.vsize_]), vsize_(other.vsize_), vused_(other.vused_)
{
std::copy(other.v_, (other.v_ + other.vused_), v_);
}
template <class T>
Field<T>& Field<T>::operator =(const Field<T> &other)
{
this->v_ = other.v_;
this->vused_ = other.vused_;
this->vsize_ = other.vsize_;
return *this;
}
FIELD MEMBERS
T *v_;
size_t vsize_;
size_t vused_;
Your copy constructor (of Field<>) seems OK, but the operator= is problematic.
Not only does it leak memory (what happens to the original v_?), but after that, two instances of Field<> hold a pointer to the same block of memory, and the one that is destructed first will invalidate the others v_ - and you can't even tell whether that has happened.
It's not always easy to decide how to deal with operator= - some think that implicit move semantics are okay, but the rest of us see how that played out with the majority of people, with std::auto_ptr. Probably the easiest solution is to disable copying altogether, and use explicit functions for moving ownership.
Your string handling in NumPair looks ok (strdup + free) and your Field container delete[] looks okay but it's hard to say because you don't show what v_ is.
eq mentions in a comment that you should also beware of how you are copying NumPairs. By default, C++ will give you an implicit member-wise copy constructor. This is where a RAII type like std::string makes your life easier: Your std::string containing struct can be copied without any special handling on your part and memory referenced in the string will be taken care of by the string's copy. If you duplicate your NumPair (by assigning it or returning it from a function for example) then the destruction of the temporary will free your strings out from under you.
Your copy constructor for Field just copies the pointers in v_. If you have two copies of a Field, all of the NumPairs in v_ will be deleted when the first Field goes out of scope, and then deleted again when the second one does.
//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.