Why the converting-constructor is called here - c++

I am trying to learn about when and where the constructors are called in the code.
I made my own, simple though, stringclass that has these possibilities:
String string1("hello world");
string1 = "Hello march!!!";
Concerning the latter one, these two constructors where called in the String-class
Called in order...
converting-constructor
copy-constructor
I can understand why the copy-constructor is called not really why the converting-constructor is called?
Here are these two constructors:
converting-constructor
String::String(const char* ch) : _strPtr(0) {
_strLen = strlen(ch) + 1;
_strPtr = new char[_strLen];
strncpy(_strPtr, ch, _strLen);
_strPtr[_strLen - 1] = '\0';
cout << "konverterings-constructor\n";
}
copy-constructor
String::String(const String& string) {
_strLen = strlen(string._strPtr) + 1; // behöver ingen "djup-kopia" av vektorlängden.
if(string.getString()) {
_strPtr = new char[_strLen];
strncpy(_strPtr, string._strPtr, _strLen);
_strPtr[_strLen - 1] = '\0'; // null-terminering
} else {
_strPtr = 0;
}
cout << "copy-constructor\n";
}
overloading member-function of assignment-operator
String String::operator=(const String& string) {
if (this == &string) { // kontrollera om objektet är lika med sig självt.
return *this;
}
cout << "......\n";
delete [] getString();
_strLen = strlen(string.getString()) + 1;
if(string.getString()) {
_strPtr = new char[getLength()];
strncpy(_strPtr, string.getString(), _strLen);
_strPtr[_strLen - 1] = '\0'; // null-terminering
} else {
_strPtr = 0;
}
return *this;
}

I can understand why the copy-constructor is called not really why the converting-constructor is called?
The converting constructor is called because when you assign, since you don't have an assignment operator that takes const char*, a temporary String is constructed from the RHS using the converting constructor, and used to assign to the LHS.
Note that the copy is down to the fact that your assignment operator returns by value. This is unusual for an assignment operator. Usually these return a reference.

Okay, first the array of const chars (which is the type of the string literal) decays to a pointer to const char. Then the converting ctor is called to construct a String from a const char *. Then copy ctor is called to construct a String in the return from your assignment operator. You should return by non-const reference to be idiomatic.

Related

What is diffrence between return reference instance and non reference instance(return mystr & vs mystr)? [duplicate]

This question already has answers here:
Difference between returning reference vs returning value C++
(3 answers)
Closed 3 years ago.
here is mystr struct
#include <stdio.h>
#include <string.h>
struct mystr {
char *str;
mystr(const char *s) {
str = new char[strlen(s) + 1];
strcpy(str, s);
printf("[1]%s\n", s);
}
mystr(const mystr &s) {
str = new char[strlen(s.str) + 1];
strcpy(str, s.str);
}
~mystr() {
delete[] str;
}
void printn() const {
printf("%s\n", str);
}
//mystr& operator+=(const char *s) this line works!
mystr operator+=(const char *s) {
char *old = str;
int len = strlen(str) + strlen(s);
str = new char[len + 1];
strcpy(str, old);
strcat(str, s);
printf("[2]%s,%s,%s\n", old, s, str);
delete[] old;
return *this;
}
};
here is main code
int main() {
mystr s = "abc";
(s += "def") += "ghi";
// only print s = abcdef
// when put & before operator+=, it prints s = abcdefghi
printf("s = %s\n", s.str);
}
Question
What is difference between
return mystr & vs mystr?
I see operator+= is called twice, but output is different.
in c++ what behavior in return instance?
The difference is if you return a copy or a reference.
With this:
mystr operator+=(const char*) {/* some code */ return *this;}
You return a copy of this object.
With this:
mystr& operator+=(const char*) {/* some code */ return *this;}
You return a reference to this object.
When you return a copy then this:
(s += "def") += "ghi";
Does not add "ghi" to s but to the copy of it, leaving s unchanged.
You can make your mystr(const mystr &s) copy constructor (and may be destructor) also to print out something to see the difference.
Here difference you are asking about is due to return the temporary calculated value need to assign to left-hand variable. So, you have to continue the chain of assignments with return of reference (mystr&).
If you return by value (mystr) then it breaks the chain of assignment.
X& operator+=(const X& rhs) // compound assignment (does not need to be a member,
{ // but often is, to modify the private members)
/* addition of rhs to *this takes place here */
return *this; // return the result by reference
}
https://en.cppreference.com/w/cpp/language/operator_assignment
Actually, whenever we overload the operator its developer responsibility to keep operator behavior the same as mentioned in language. As we develop the piece of code that can be used by thousands of users, each doesn't have time to check the implementation of our code.
The principle of least astonishment means that a component of a system should behave in a way that most users will expect it to behave; the behavior should not astonish or surprise users.
What are the basic rules and idioms for operator overloading?

Constructor was called when assignment operator not implemented

I am practicing 'String' class implementation (C++) in Visual Studio 2015.
I have 3 constructors in my class and not any assignment operator.
String();
String(char _c);
String(const char* _pc);
In main(), i am deliberately using assignment operator to check behavior of the code.
To my surprise, it is not giving any error and uses the constructor String(const char* _pc) to assign value to the object.
Also, at the end of the scope, it is calling the destructor twice.
What is compiler doing behind the curtain in this case? and why?
Here is my code:
class String {
private:
int capacity;
char* start;
public:
//Constructors
String();
String(const char* _pc);
//Destructor
~String();
}
String::String() :start(nullptr), capacity(0) {}
String::String(const char* _pc) :capacity(1) {
const char* buffer = _pc;
while (*(buffer++))
capacity++;
int temp_capacity = capacity;
if (temp_capacity)
start = new char[temp_capacity];
while (temp_capacity--) {
start[temp_capacity] = *(--buffer);
}
}
String::~String() {
if (capacity == 1)
delete start;
if (capacity > 1)
delete[] start;
}
int main() {
String s;
s="Hello World";
return 0;
}
What is compiler doing behind the curtain in this case?
Given s="Hello World";,
A temporary String is constructed (implicitly converted) from "Hello World" via String::String(const char*).
s is assigned from the temporary via implicitly-declared move assignment operator (String::operator=(String&&)).
BTW you might mark String::String(const char*) explicit to prohibit the implicit conversion which happened at step#1.

C++ - calling to constructor on exist object

I saw some code that reconsruct Object on c++.
from GeeksForGeeks :
#include<iostream>
#include<string.h>
using namespace std;
class String
{
char *p;
int len;
public:
String(const char *a);
};
String::String(const char *a)
{
int length = strlen(a);
p = new char[length +1];
strcpy(p, a);
cout << "Constructor Called " << endl;
}
int main()
{
String s1("Geeks"); // line 1
const char *name = "forGeeks";
s1 = name; // line 3
return 0;
}
Now, after line 3 s1 is a different object?
I always thought that after you construct object, you can't dereference it.
What you see is an assignment.
A copy assignment operator is automatically generated in your class, since you don't define one yourself. From the page I linked to:
If no user-defined copy assignment operators are provided for a class
type (struct, class, or union), the compiler will always declare one
as an inline public member of the class.
There is actually no dereferencing on line 3: there is only a replacement of an object with an another. The line 3 calls the constructor of String and assign the object to s1. So two different instances of String are being created but the constructor is not ´recalled´ on the first object but assign the created one to s1. The operator = is used as its default behavior which is to find if there is a constructor that matches the type given to the = operator.
On a side note, the dynamic memory is not freed at any point in the code making it a bad code sample.
Let's break it down.
s1 = name;
First, the compiler will construct a new String object using the constructor String(char const*). Then it uses the copy assignment operator to update s1 with this newly created object.
Since you did not define this operator, it simply does a copy of the class members, i.e. p and len: that's the default implementation the compiler generates for you. The old object is not cleaned up before so you are leaking memory... You should thus write your copy semantics using the copy and swap idiom:
class String {
char *p;
int len;
public:
// Your constructors...
// Swap function
friend void swap(String& s1, String& s2) {
using std::swap;
swap(s1.p, s2.p);
swap(s1.len, s2.len);
}
String(String const& other) : p(new char[other.len]()), len(other.len) {
std::copy(other.p, other.p + len, p);
}
String& operator=(String other) {
swap(*this, other);
return *this;
}
// And finally, a destructor:
/* virtual */ ~String() {
delete [] p;
}
};

Why destructor is called when any of these object not going out of scope?

When I remove The Destructor from code the output come as i desired but if i free the space manually program become mad :( Please some one help me, I'm Using Code::Blocks IDE and Running in Linux mint OS
#include<iostream>
#include<cstring>
using namespace std;
class str
{
char *p;
int len;
public:
str() {
len=0;
p=NULL;
}
str(const char *s);
str(const str &s);
~str() {
cout<<" Distructor Called ";
delete p;
}
friend str operator+(const str &s,const str &t);
friend bool operator<=(const str &s,const str &t);
friend void show(str &s);
};
str::str(const char *s)
{
len=strlen(s);
p=new char[len+1];
strcpy(p,s);
}
str::str(const str &s)
{
len=s.len;
p=new char[len+1];
strcpy(p,s.p);
}
void show(str &s)
{
cout<<s.p;
}
str operator+(const str &s,const str &t)
{
str tem;
tem.len=s.len+t.len;
tem.p=new char[tem.len+1];
strcpy(tem.p,s.p);
strcat(tem.p,t.p);
return tem;
}
bool operator<=(const str &s,const str &t)
{
if(s.len<=t.len)
return true;
else
return false;
}
int main()
{
str s1="New ";
str s2="York";
str s3="Delhi";
str string1,string2,string3;
string1=s1;
string2=s1+s2;
string3=s1+s3;
cout<<"\nString1 = ";
show(string1);
cout<<"\nString2 = ";
show(string2);
cout<<"\nString3 = ";
show(string3);
cout<<"\n\n";
if(string1<=string2) {
show(string1);
cout<<" Smaller Than ";
show(string2);
cout<<"\n";
} else {
show(string3);
cout<<"Smaller Than ";
show(string1);
cout<<"\n";
}
return 0;
}
Read about the Rule of Three.
When you don't declare the assignment operator, a default one is generated by the compiler which does the following:
Assign all the object's members from the corresponding members of the assignment operator's argument, calling the copy assignment operators of the object's class-type members, and doing a plain assignment of all non-class type (e.g. int or pointer) data members.
First of all, the above bold text applies to char *p in your class.
In your operator+ function, tem is an object on stack. When the function ends, tem goes out of scope, and its destructor is called.
So what happens is string1's p is assigned tem's p as per the default assignment operator generated by the compiler, meaning string1's p points to the same memory location as tem's p, which was deallocated after it went out of scope! Hence, string1 does not have the expected value. Later, when string1 goes out of scope and its destructor is called, delete is called on the same memory location for the second time, hence leading to the error shown. Similarly, for string2.
Things will be fine if you overload the assignment operator like this:
void str::operator=(const str&s) {
delete[] p;
len=s.len;
p=new char[len+1];
strcpy(p,s.p);
}
In this case, tem's p will be copied over before its destructor is called.
NOTE:
It works when you remove the destructor because the default
destructor generated by the compiler does not deallocate the
allocated memory, but this will leak memory, which is BAD.
There is another major flaw in your code. Use delete[] for
deallocating arrays.
You have not overloaded the assignment operator. Because of this the same pointer getting assigned and getting deleted twice which is causing the exception.

Const data type cannot be assigned into a non-const data type

I am trying to make a really simple string class with a copy constructor, the problem that i am having is that i am trying to send a data type/object as a constant but whenever i try to assign it to the same non-constant data, the compiler complains.
I don't get why would compiler complain, i am just trying to copy the data, i am not modify it.
Header
class MyString{
private:
char* thestring;
MyString* ms;
public:
MyString();
MyString(const char* str);
MyString(const MyString& str);
~MyString();
MyString& operator=(const char* str);
};
CPP
MyString::MyString(){
thestring = '\0';
}
MyString::MyString(const MyString& str){
ms = str;
}
MyString& MyString::operator=(const char* str){
MyString* temp = new MyString();
temp->thestring = str;
return temp;
}
MyString::MyString(const char* str){
}
MyString::~MyString(){
}
here are the erros:
no suitable conversion function from "const MyString" to "MyString *"
exists 9
a value of type "const char *" cannot be assigned to an entity of type
"char *" 14
a reference of type "MyString &" (not const-qualified) cannot be
initialized with a value of type "MyString *" 15
'MyString::operator=' : must return a value 16
First, you do not need ms member in your class: it serves no purpose, and it is used only in your (incorrect) copy constructor. Remove ms, and rewrite the code as follows:
MyString::MyString(const MyString& str) {
thestring = strdup(str.thestring);
}
Note that now your code violates the rule of three: once you add a copy constructor, you also need a matching assignment operator and a destructor:
MyString& MyString::operator=(const MyString& str) {
if (this != &str) {
free(thestring);
thestring = strdup(str.thestring);
}
return *this;
}
MyString::~MyString() {
free(thestring);
}
Finally, I would rewrite your default constructor like this:
MyString::MyString()
: thestring(0) {
}
Essentially, this is not different, but an initialization list is more canonical.
Line 9: ms is a MyString*, but str is just a const MyString& (ie, not a pointer).
Line 14: You cannot assign a const char* value to a char*, as this would potentially allow you to change it:
void foo(const char* dont_change_this) {
char* s = dont_change_this;
s[0] = '!'; // you changed it!
}
Line 15: Once again, a simple pointer mis-match. The return type of op= is MyString&, but temp has type MyString*.
But you're not just trying to copy the data, you're trying to strip it of its constness. In other words, you're attempting to assign a non-const pointer with a const pointer. This would give you the ability to potentially change the value of what you intended to be "const".