Conversion constructor - c++

Can any one tell me how the char* member gets deleted after conversion constructor is called.
The output is Debug Assertion Failed
class String
{
public:
char* m;
String()
{
m = NULL;
}
String(const char* str)
{
m = strdup(str);
}
String(const String& I)
{
m = strdup(I.m);
}
~String()
{
delete m;
}
};
void main()
{
String s;
s = "abc";
s = "bcd";
}

The problem is that you have not implemented an assignment operator. So when you do this
s = "abc";
you end up with two String objects (one of them a temporary) holding a pointer to the same address. They both try to delete the same object. You need to follow the rule of three.
Note: as #kolrabi has pointed out, you should be calling free on a pointer allocated with strdup, not delete.

Let's analyze s = "abc":
First of all, this is an assignment, not an instantiation, because s has already been declared.
So the compilation solution for this would be to create a temporary String object with "abc" as the argument to the String constructor, and then call the String assignment operator in order to copy that temporary object into s.
Now, since you have not implemented an assignment operator for this class, the default assignment operator is called, and simply copies each one of the member variables from the temporary String object into s.
Finally, the temporary String object is destroyed and the memory pointed by its m variable is deallocated. As a result, you end up with s.m pointing to an invalid piece of memory.

Related

Why is the destructor called after assignment?

Why is destructor being called here after the line mystring = "Hello, there!";
It is not like it is going out of scope yet. I am definitely missing some quirk of C++!
I know that line calls the default copy constructor, is the destructor always called after a copy constructor returns?
Just as a side note, I am using C++03, no C++11 yet.
EDIT : Also please note that I am aware of the double deletion that this below program causes. I am experimenting here. Just wanted to bring to your notice.
class MyString
{
private:
char* mystring;
int m_length;
public:
MyString(const char* str="")
{
assert(str);
m_length = strlen(str) + 1;
mystring = new char[m_length];
for (int i = 0; i < m_length; ++i)
mystring[i] = str[i];
mystring[m_length-1] = '\0';
}
~MyString()
{
delete[] mystring;
}
};
int main()
{
MyString mystring("");
mystring = "Hello, there!";
cout << "Destructor not yet called ";
}
Since you do not have a assignment operator for your class which takes a string literal mystring = "Hello, there!"; is turned into a 3 part operation.
First it has to construct a temporary object from the string literal.
Then it takes that temporary and uses it with the default copy(pre C++11)/move(post C++11 if not deleted otherwise) assignment operator the compiler generated for the class.
Then it has to destroy the temporary object that it created. That is why you would see a call to the destructor at the end of that expression.
Do note that since the temporary object is destroyed after
mystring = "Hello, there!";
That the pointer mystring holds is now deleted and you can no longer access it. It will also cause a double deletion when it is destroyed which is undefined behavior and will cause complications.

Why not only one? Copy constructor and assignment operator

I understand which is invoked in what situation...
Sample a;
Sample b = a; //calls copy constructor
Sample c;
c = a; //calls assignment operator
My question is Why these 2 different things exist at all? Why can't only one of the two take care of both situations?
No, they are different.
Copy constructor is used for constructing a new object (from another object). In this case you just need to initialize the members.
Assignment operator is used for an existing object (you may have constructed it by default constructor etc), and then assign it by another object. In this case you need to re-initialize members, sometimes means destroying and initializing them again.
Even so, the functionality of them are so similar, so you can share their implementation usually. Such as: What is the copy-and-swap idiom?
The copy constructor is invoked on creation, that means you don't have to take care of old resources in your object. The assignment operator on the other hand has to free the old resources. Besides they have different semantical meaning.
Suppose the String class:
class String
{
char *m_str;
size_t m_len, m_alloced;
public:
String(const char *str = "")
{
m_len = strlen(str);
m_alloced = m_len + 1;
m_str = (char *)malloc(m_alloced);
strcpy(m_str, str);
}
String(const String &other)
{
m_len = other.m_len;
m_alloced = m_len + 1;
m_str = (char *)malloc(m_alloced);
strcpy(m_str, other.m_str);
}
String &operator =(const String &rhs)
{
if (m_alloced < rhs.m_len + 1)
{
m_alloced = rhs.m_len + 1;
m_str = (char *)realloc(m_str, m_alloced);
}
m_len = rhs.m_len;
strcpy(m_str, rhs.m_str);
return *this;
}
const char *get() const
{
return m_str;
}
};
(live example)
Appearently, copy constructor and copy assignment operator does different things. Look at the String::String(const String &other).
m_len = other.m_len;
m_alloced = m_len + 1;
m_str = (char *)malloc(m_alloced);
strcpy(m_str, other.m_str);
It initializes its object. Set m_len, m_alloced, and m_str, and strcpy the string.
However, the String &String::operator =(const String &rhs) does -
if (m_alloced < rhs.m_len + 1)
{
m_alloced = rhs.m_len + 1;
m_str = (char *)realloc(m_str, m_alloced);
}
m_len = rhs.m_len;
strcpy(m_str, rhs.m_str);
return *this;
modify its object. Allocate more memory if required, and reset m_len and recopy the string.
Copy constructor is called when the object is created, and does initialize its object.
But copy assignment operator is called after the object is created, and does modify its object.
For example, look at this code.
String str1 = "asdf";
String str2 = str1;
String str3 = "12";
str3 = str1;
(it's also in the live example)
str1 is initialized by String::String(const char *). As you know, it'll contain "asdf".
str2 is initialized by copy constructor, String::String(const String &other). By the copy constructor, str2 will contain the same content.
str3 is initialized by String::String(const char *), like str1. However, in line 4, it is modified by copy assignment operator. So, str3 contains "12" at first, but its content will be modified into "asdf", by copy assignment operator.
Well, you could technically get away with just having a copy-constructor and a destructor, but that would require that every time you wanted to do an assignment you would have to destroy the object and then reconstruct it. This would become HIGHLY inefficient in the vast majority of use cases.
We cannot just have an operator= either, as you have no idea what the left-hand-side of the operator will be if it has not yet been constructed. It's members would probably contain garbage data and "shit would hit the fan".
Thus, you can think of the need for both an operator= and a copy-constructor as an optimization.
That being said there are a few design-patterns that can reduce the amount of code you have to write. For example, assuming you have a copy-constructor, a destructor and a swap-function implemented for your class. You could implement operator= using a copy-swap operation:
MyClass & operator=( MyClass rhs ) { // notice the call by value, this will
// implicitly call the copy-constructor.
swap(*this, rhs);
return *this;
}
Whilst this operator has strong exception safety, it is worth to notice that it may be much less efficient than reusing preallocated resources (which a more advanced operator= might do).
Basically, they are used in different situations, many correct answer, i just wanna add something to clear out where the copy constructor is also used:
For example:
void test(Fraction in){
//Do something here
}
Fraction test2(){
Fraction a(1, 2);
//Do something here
return a; // construct a return value by copy a
}
int main()
{
Fraction a(2, 3);
Fraction b(a); //construct b by copy a
Fraction c=a; //construct c by copy a
test(a); //construct in by copy a
}

Copy Constructor for char *data member using strcpy

I have doubt regarding copy constructor for a char* data member.
I have my code as,
#include<iostream>
using namespace std;
class Test
{
char *str;
int length;
public:
Test(){}
Test(char *a)
{
length = strlen(a)+1;
str = new char(length);
str = strncpy(str,a,length);
}
Test(const Test &t)
{
length = t.length;
if(t.str)
{
str = new char(length);
str = strncpy(str,t.str,length);
}
else
str = 0;
}
void out(){cout<<str;}
};
int main()
{
Test t("Test");
Test t1 = t;
t1.out();
return 0;
}
In case of constructor and copy constructor instead of using strncpy to copy the data member value, if I use:
Test(char *a)
{
str = new char();
str = a;
}
Test(const Test &t)
{
if(t.str)
{
str = new char();
str = t.str;
}
else
str = 0;
}
Will this also work? If yes, which method is preferable?
Not only the second version won't work, it will also provide you with a memory leak.
You first allocate memory to str, then you put in str the pointer pointing at the other object's string which means:
1. You no longer can access the memory you allocated.
2. Once you delete the string in one of the objects, it will be deleted in the other one too.
(*) you should also add an assignment operator.
In case of constructor and copy constructor instead of using strncpy to copy the data member value, if I use [code doing pointer copy]
I see that instead of strncpy you directly assign the pointer to the passed in string pointer. Will this work? No, what you're doing is just a pointer copy and not what the data the pointer is pointing to i.e. you need to deep copy and not shallow copy. You can use strncpy or std::copy_n.
Multiple other issues:
Use size_t instead of int to store sizes
Use constructor initilization list instead of assignment inside constructor body
Know the difference between new char [len] vs new char(); former allocates an array while the latter a char initialized to 0
Know that when you manage objects in free store, you've to implement an assignment operator, destructor, etc. a.k.a The Rule of Three/Five.
Allocating memory for a pointer and then losing its reference by allocating something else without releasing it will leak memory
Using std::string will be better since it's tried and tested

function return temporary object misbehaving

OK, very simple String class, which holds constant strings (i.e. can't be changed once initialized), implements the copy ctor and concatenation function conc. It's that function that's giving me trouble, because I really cannot figure out why a local variable I make isn't passed normally as return value.
Code:
class String
{
public:
String(char*);
String(const String& other);
~String();
friend String conc(const String&, const String&);
friend std::ostream& operator<<(std::ostream&, const String&);
private:
const char* const str;
};
String::String(char* aStr) : str(aStr) {}
String::String(const String& other) : str(other.str) {}
std::ostream& operator<<(std::ostream& out, const String& s)
{
out<<s.str<<"\n";
return out;
}
String::~String()
{
delete str;
}
String conc(const String& s1, const String& s2)
{
int n = strlen(s1.str) + strlen(s2.str);
int i, j;
char* newS = new char[n+1];
for(i = 0; i < strlen(s1.str); ++i)
{
newS[i] = s1.str[i];
}
for(j = 0; j < strlen(s2.str); ++j)
{
newS[i+j] = s2.str[j];
}
newS[i+j] = '\0'; //newS is made correctly
String tmp(newS); // the tmp object is made correctly
return tmp; // here tmp becomes something else --- Why??
}
int main()
{
String s1("first");
String s2("SECOND");
String s3 = conc(s1, s2); //here the copy ctor should be called, right?
std::cout<<s3;
_getch();
}
As you can see in the comments, the problem is in the conc function at the end. I have made the function return a String, and not String& on purpose, given that the value it returns shouldn't be an lvalue...
Please explain & help, thanks!:)
There are memory management problems all over the place here. Each String object should own its own memory. That means that String::String(char*) needs to allocate an array of char and copy the contents of the input string; String::String(const String&) needs to allocate an array of char and copy the contents of the input string; and String::operator= needs to delete its own string (unless it's the same as the input string), allocate an array of char, and copy the contents of the input string. Finally, String::~String() should delete[] the array of char.
It is not what you think: the problem is the deletion of the temp. You call delete instead of delete[] on an array allocated with new[] - an undefined behavior.
Once you fix that error, you will have other errors related to Strings initialized with string literals: passing them to delete[] is also undefined behavior.
The root cause of the problem is that your class does not let you differentiate between the memory that you must release and the memory that you must not release. You should do it uniformly, for example by always copying the content into an array that you allocate inside the constructor.
There are several problems with your class:
Your String( char * ) constructor assumes ownership of the pointer passed to it, so if you construct the object with a string literal the destructor will try to delete it, leading to undefined behavior.
Your copy constructor assumes ownership of the string belonging to the object being copied, instead of making its own copy, due to which the string will be double deleted.
In the conc function you allocate memory using new[] but then you delete it instead of delete[] leading to undefined behavior
The member variable str is supposed to be a char array, so the destructor must delete[] it instead of delete
You need to change your constructor so it's making a copy of the C string, for example:
String::String(const String& other) : str(strdup(other.str)) {}
If you use strdup above you should change your destructor appropriately, so instead of using delete you use free
String::~String() { free(str); }
It would be a good idea to change your other constructor so it's not acquiring the C string, but making a copy of it as well, this way behaviour of all constructors would be more consistent and safer, in general:
String::String(const char* aStr) : str(strdup(aStr)) {}
If you make it this way, it will work correctly whether the client code is passing you pointer allocated with malloc or new.
Replacing strdup and free with more new and delete should be easy, I'm leaving it to you as an exercise.
When you return a temporary from a function, a copy is made for the return value and the temporary is destroyed. (Sometimes the copy can be skipped via return value optimization but I don't think that's happening here).
Because your copy constructor copies the character array pointer, both objects are now pointing to the same memory. When the temporary is destroyed, it destroys the character array and now the returned object has a dangling pointer.
One of the big benefits of an immutable string class is that it can easily share buffers as you do here, without the overhead of copying. You just need a mechanism for counting the references to the buffer so it isn't deleted until the last object is deleted. You can use a std::shared_ptr with a custom deleter instead of the char * pointer.
You should also look into the Rule of Three to make sure you're implementing all the necessary functions.

Why is this destructor being called immediately after creation?

I have the following class:
class FixedByteStream {
public:
FixedByteStream() : size(0), address(NULL), existing(false) {}
FixedByteStream(int length) : existing(false) {
size = length;
address = new char[length];
}
FixedByteStream(int length, char* addr) : existing(true) {
size = length;
address = addr;
}
FixedByteStream(string* str, bool includeNull = false) : existing(true) {
size = (*str).length();
address = const_cast<char*>((*str).c_str());
if (includeNull){
++size;
}
}
~FixedByteStream() {
if (existing == false) {
delete [] address;
}
address = NULL;
}
int getLength() {
return size;
}
char* getAddressAt(int index) {
return &(address[index]);
}
char& operator[] (const int index) {
return address[index];
}
operator char*() {
return address;
}
private:
bool existing;
int size;
char* address;
};
And a very simple test that is able to produce the issue:
FixedByteStream received;
received = FixedByteStream(12);
received[0] = 't';
Valgrind warns about an invalid write, and debugging has shown why. FixedByteStream received; calls the constructor with no arguments (which is kind of stupid because it can't do anything). received = FixedByteStream(12); calls the constructor with the integer argument... and then immediately calls the destructor on itself, invalidating the object. It still works for some reason, but I'd rather it not be placed in such an odd predicament that throws warnings.
So, why is it being called there? I could somewhat understand if the destructor were called first, to get rid of the useless temporary object (not that it needs to), but I have used that kind of declare-now-assign-later pattern practically everywhere and never had such an issue before.
You are missing an assignment operator. Remember the rule of three (or five).
The problem is roughly like this:
T t; // default constructed t
t = T(2); // T(2) constructor with a single argument, assignment operator= called with this == &t
You provide no assignment operator so the pointer value in the temporary is simply copied into t and then the memory pointed to is deleted in the destructor of the temporary.
Also: Don't have a default constructor, if the object constructed is invalid.
If you object has any user defined constructor it is always constructed using a constructor. Just defining an object without any constructor arguments uses the default constructor independent of whether the object is being overwritten afterwards. That is
FixedByteStream received;
will call the default constructor. The next line is a bit more interesting:
received = FixedByteStream(12);
This line create a temporary FixedByteStream with the argument 12. Internally this will allocate some memory but since temporaries are destroyed at the end of the full expression (in this case essentially when the semicolon is reached) that won't you do much good. Once this temporary object is constructed it is assigned to received using the automatically generated copy assignment which would look something like this if you'd write it manually:
FixedByteStream& FixedByteStream::operator= (FixedByteStream& other) {
this->existing = other.existing;
this->size = other.size;
this->address = other.address;
return *this;
}
That is, once this assignment is executed, you have to identical copies of FixedByteStream, one of which is about to be destroyed and will release the resources just allocated. This is clearly not what you want, i.e. you definitely need to implement the copy assignment operator to make your class well-behaved. In general, the presence of a destructor which does anything interesting is a good hint at the fact that you'll need an assignment operator as well. In fact, there is another one of the generated operations, namely the copy constructor, which does roughly what the copy assignment does except that it copy constructs the members instead of assigning them. This is also not what you want with your class.
Now the interesting question becomes: how can FixedByteStream be fixed? Effectively, you'll need either to use reference counting to keep track of how many objects are currently looking at the FixedByteStream, allocate a copy of the content, or you need to use move semantic support (aka rvalue references) which is only available in C++2011. Unless you really know what you are doing I'd recommend copying the stream in all cases and leave a more advanced approach for later.
Step by step:
//create a new object using the default constructor
//I don't see why you think it's stupid that the constructor is called
//it's doing what you're telling it to do
FixedByteStream received;
//FixedByteStream(12) creates a temporary object
//you then copy this object in the received object you already have
//you're using the default operator =
//the temporary object is deleted after it is copied to received
received = FixedByteStream(12);
//received is a valid object
received[0] = 't';
EDIT:
As I see there's a lot of wrong answers for this question, I'll explain further. I might get some hate for this, but this is a pretty important concept and I downvoted so that a wrong answer doesn't get accepted and taken from granted.
You're basically initializing some object on the stack.
I'll simplify your case:
class A
{
A() {}
A(const A& other) {}
A& operator = (const A& other) {}
};
Let's talk about scope:
{ //begin scope
A a; //object a is created here
//default constructor is called
} //a is destroyed here
//destructor is called
So far so good.
Now, assignment:
{
//two objects are created with default constructor
A a;
A b;
//object b is assigned to a
//operator = will be called
//both objects are still alive here
a = b;
//...
} // a and b will be destroyed, destructor called
On to the last part:
{
A a;
a = A();
}
is pretty much equivalent to:
{
A a;
{
A b;
a = b;
}
}
When you call a = A(), A() creates a temporary object which is assigned to a and then destroyed.
So object b in my simplification is the temporary object that gets destroyed. Not a, your original, therefore a is still valid.
Not the assignment operator declaration. If you don't define one, a default is used. You probably want to write your own in this case.
FixedByteStream(12) is assigned to received through the default operator=. Notice that you didn't allocate FixedByteStream(12) in the heap by using new, but rather allocated it in local scope without specifying a name for the variable that would hold it.
Your code is somewhat similar to:
FixedByteStream received;
FixedByteStream temp(12);
received = temp;
received[0] = 't';
Only in my example temp has a name and its scope is the entire function, and in your test code temp doesn't have a name, it exists for one line only and then gets destroyed.
The FixedByteStream(12) object you've created cannot be used after this line because it's not even a named varaible.
Object is already initialized on this line
FixedByteStream received;
On line
received = FixedByteStream(12);
You reinitialize it. The correct way to do this is:
FixedByteStream received(12);
// Or
FixedByteStream *received;
received = new FixedByteStream(12);
(I'd definitely go for first one)
It seems you don't understand object lifecycle and mistakenly interpret this code as a Java code.
When you write FixedByteStream received; an object of type FixedByteStream is created using the no-argument constructor. And when you write received = FixedByteStream(12); another object is created, = operator is called and the newly created object is desctructed.
Also you didn't override operator= so the object is copied by bytes, which is not correct.