Why is destructor called in Friend function - c++

Why is Destructor Called in this Friend function show() C++?
Also, how should the character pointer be initialized, it was set as 0...
The full code with main is here https://justpaste.it/5x7fy
#include<iostream>
using namespace std;
#include<string.h>
class String
{
public:
char *p;
int len;
String()
{
cout << "empty constructor" << endl;
len=0;
p=0;
}
// constructor
String(const char *s) {
len=strlen(s);
p=new char[len+1];
strcpy(p,s);
}
friend String operator+(const String&s, const String&t);
friend int operator<=(const String&s, const String&t);
friend void show(const String s);
~String() {delete p;}
};
void show(const String s)
{
cout<<s.p<<endl;
}
Edit, read up on copy constructor and added one as:
// copy constructor
String(const String &s)
{
len=s.len;
p=new char[len+1]; // s.p;//
strcpy(p,s.p);
}
The friend function parameter was passed by value before and the variable left the show function scope, therefore the destructor was called, now it is passed by reference.
friend void show(const String & s);
...
void show(String & s)
{
cout<<s.p<<endl;
}
Edit updated the initialization of the character pointer in the empty constructor.
String() {
p = new char[1]{'\0'};
len = 1;
};
[latest source]: https://www.mediafire.com/file/31gb64j7h77x5bn/class38working.cc/file

The destructor is called because s is passed by value. That is, when you call show(something), that something is copied into s, which is later destroyed when execution of show ends.

Your friend function show takes the String parameter per value, which means that whatever argument is passed to the function, a local copy is created and used inside the function. Of course, this local copy is destroyed - again when the show() function ends.
If you pass the string by reference (const string**&** s), you won't get an extra temp copy nor any destruction of that.

Related

Syntax and overloading copy constructor

I am new to the topic of overloading copy constructors and I just wanted someone to look at my code for my class and see if I am overloading my copy constructor correctly. It is only using a single string as user input. Also, do I need the '&' or not?
class TODO {
private:
string entry;
public:
List* listArray = nullptr;
int itemCount = 0, currInvItem = 0;
int maxLength = 22;
TODO() { entry = ""; };
TODO(const string& ent) { setEntry(ent); }; // Is this correct?
void setEntry(string ent) { entry = ent; };
string getEntry() const { return entry; };
void greeting();
void programMenu();
void newArray();
void getList();
void incList();
void delTask();
string timeID();
string SystemDate();
friend istream& operator >>(istream& in, TODO& inv);
friend ostream& operator <<(ostream& out, TODO& inv);
void componentTest();
void setTask(string a);
string getTask();
bool validTask(string a);
bool notEmpty(string e);
};
That's correct, but it's just a constructor of TODO taking a const reference to a string. You can test it here.
Passing const string& ent (by const reference) is not a bad idea. Another option would be to pass string ent (by value), and move that string when initializing entry, i.e. : entry{ std::move(ent) }. As here.
The class TODO has a default copy constructor. Check the line at the Insight window here (you'll have to click Play first).:
// inline TODO(const TODO &) noexcept(false) = default;
The default copy constructor would just copy the members, including the List pointer, but not the List elements (shallow copy). Notice both instances of TODO would be pointing to the same List elements, and any operation on them would affect both instances.
Should you want to implement a custom copy constructor, the syntax would be (see here):
TODO(const TODO& other) {
std::cout << "custom copy_ctor\n";
*this = other;
// Copy listArray elements
...
}

Returned reference to string literal (passed as parameter) is accessible in calling function, however, returned object storing the reference is empty

I'm passing a string literal to a function that simply returns back a const reference to it. In the calling function, the string is accessible and printed.
However, in another function, I'm instantiating a class that holds a const reference to the string literal. Returning this object back prints nothing in the calling function.
Environment: Visual Studio 2017 (/std:c++=17)
This seems unusual. Any leads?
class Test {
private:
const string& str_;
public:
Test(const string& str)
: str_{str}
{}
Test(const Test&) = delete;
Test& operator=(const Test&) = delete;
friend ostream& operator<<(ostream& out, const Test& t) {
return (out << t.str_);
}
};
const Test& returnString2(const string& str) {
return Test{ str };
}
const string& returnString1(const string& str) {
return str;
}
void testRef() {
cout << "testRef: " << returnString2("Roofus") << "\n";
}
In:
const Test& returnString2(const string& str) {
return Test{ str };
}
You are creating a temporary Test, that you are returning a reference to. But this temporary is destroyed at the end of the function resulting in undefined behaviour. This has nothing to do with the passed in str ref - its the temporary Test object that has been destroyed. The reference to str is still happily exiting.
In:
const string& returnString1(const string& str) {
return str;
}
You are simply returning the ref passed in - this still exists when the function returns and so cout << "testRef: " << returnString2("Roofus") << "\n"; is fine.
In fact a good compiler would warn you about this (not sure what visual studio does - but I am sure you can turn such warnings on): https://godbolt.org/z/E4s46bdEP

How is a std::string parameter passed from a raw character array literal?

First of all, I do not really know how I put title on this question..
So we have this code:
class Example5 {
string* ptr;
public:
Example5 (const string& str) : ptr(new string(str)) {}
~Example5 () {delete ptr;}
// access content:
const string& content() const {return *ptr;}
};
int main () {
Example5 foo ("Example");
cout << "bar's content: " << foo.content() << '\n';
return 0;
}
So the constructor of the class Example5 is initializing the pointer ptr to be a pointer to str, right?
Is it an optimal way to have const string& str as the parameter instead of string str? I mean since str is used as something to be pointed to by ptr, why is the value of the argument not just get copied instead of making a reference to an unnamed entity/the string literal? Is this optimal?
So the constructor of the class Example5 is initializing the pointer ptr to be a pointer to str, right?
No! It creates a new std::string instance and copies what's passed in the parameter.
why is the value of the argument not just get copied instead of making a reference to an unnamed entity/the string literal?
Good question, yes.
Is this optimal?
No.
The usual way would be simply not to use a pointer at all:
class Example5 {
string s;
public:
Example5 (const string& str) : s(str) {}
// access content:
const string& content() const {return s;}
};
To avoid taking a copy (if that's actually your concern) you could alternatively write
class Example5 {
string s;
public:
Example5 (string str) : s(std::move(str)) {}
// access content:
const string& content() const {return s;}
};

Cout not returning any output

I'm learning c++ and found a problem that I dont understand. I have this simple code:
#include <iostream>
#include <vector>
class Person
{
string * name;
public:
Person(const string & n) : name {new string {n}} {}
~Person() {delete name;}
string getName() const {return *name;}
};
int main()
{
vector<Person> people;
people.push_back(Person("Tom"));
cout << "Name is: " << people.back().getName() << endl;
return 0;
}
When I run it, I have no output. Dont know why? However, when I do simillar, but without vector everything is ok:
int main()
{
Person tom {"Tom"};
cout << "Name is: " << tom.getName() << endl;
return 0;
}
As other said, better to do without pointers. However, if you wondering what is happening, the reason for what you get is that in this line people.push_back(Person("Tom")); Person object is created, and its copy passed to vector. However, once the object is copied, destructor is executed which deletes the string.
With your usage of pointers, both the original Person object and its copy point to the same string in memory. String gets deleted by destructor, and name pointer in the copy does not point to anything. Thus you get undefined behaviour.
To rectify this issue, either dont use pointers, or you need to define your own copy constructor. For example:
class Person
{
string * name;
public:
Person(const string & n) : name {new string {n}} {}
// copy constructor which makes new string in memory
//based on the original string.
Person(const Person & other) {
name = new string(other.getName());
}
~Person() { delete name; }
string getName() const {return *name;}
};
You are using wrong type. Your string is already a string type. Write the code like this.
class Person
{
public:
Person (const string& n) : name(n) { }
~Person() {}
string getName() const { return name; }
private:
string name;
};
If you insist to use pointer in your member variable, you shall overwrite the copy constructor and overload assign operator.
Give you an example:
class Person
{
public:
Person (const char* n) : name(new char[strlen(n)+1]) { strcpy(name, n); }
Person (const Person& p) : name(new char[strlen(p.name)+1]) { strcpy(name, p.name); }
~Person() { delete [] name; }
Person& operator=(const Person& p)
{
if ( &p == this ) return *this;
delete [] name;
name = new char[strlen(p.name)+1];
strcpy(name, p.name);
return *this;
}
string getName() const { return name; }
private:
char* name;
};
The reason why your code is buggy has already been explained, but if you have C++11, you can use emplace_back:
people.emplace_back("Tom");
Still, using pointers instead of a plain member variable is just unnecessarily complicating your program. The less memory management you have to do, the better. Read about the Rule of Zero. Better yet, if your getName() function doesn't do anything special, remove it and just make name public.

declaration is incompatible, beginner c++

I just need a little help on this assignment. I have to redefine operators to work with strings. I'm starting with the == operator and I have it declared in my header file, however when I go to define the function in my cpp file, it says it's incompatible with the declared function. It's probably a stupid mistake, I just don't understand this sometimes.
string.h header file
#pragma once
#include <iostream>
#include <string>
using namespace std;
#define NOT_FOUND -1
// C++ String class that encapsulates an ASCII C-string
class String
{
public:
// Default constructor
String();
// MUST HAVE: Copy-constructor that performs deep copy
String(const String& source);
// Init-constructor to initialize this String with a C-string
String(const char* text);
// Init constructor, allocates this String to hold the size characters
String(int size);
// Destructor
~String();
bool& compareTo(const String& cmp1);
// Assignment operator to perform deep copy
String& operator = (const String& source);
// Assignment operator to assign a C-string to this String
String& operator = (const char* text);
// Returns a reference to a single character from this String
char& operator [] (int index) const;
// Comparison operators
bool operator == (const String& compareTo) const;
string.cpp file
#include "string.h"
#include <string>
#include <sstream>
using namespace std;
// Default constructor
String::String()
{
Text = NULL;
}
// MUST HAVE: Copy-constructor that performs deep copy
String::String(const String& source)
{
Text = NULL;
// Call the assignment operator to perform deep copy
*this = source;
}
// Init-constructor to initialize this String with a C-string
String::String(const char* text)
{
Text = NULL;
// Call the assignment operator to perform deep copy
*this = text;
}
// Init constructor, allocates this String to hold the size characters
String::String(int size)
{
Text = new char[size];
}
// Destructor
String::~String()
{
delete[] Text;
}
// Assignment operator to perform deep copy
String& String::operator = (const String& source)
{
// Call the other assigment operator to perform deep copy
*this = source.Text;
return *this;
}
// Assignment operator to assign a C-string to this String
String& String::operator = (const char* text)
{
// Ddispose of old Text
delete[] Text;
// +1 accounts for NULL-terminator
int trueLength = GetLength(text) + 1;
// Dynamically allocate characters on heap
Text = new char[trueLength];
// Copy all characters from source to Text; +1 accounts for NULL-terminator
for ( int i = 0; i < trueLength; i++ )
Text[i] = text[i];
return *this;
}
***bool& String::operator ==(string cmp2)***
{
};
Your compareTo declaration has const while definition has no const, which means they have definition has different signature with declaration:
bool& compareTo(const String& cmp1);
^^^
bool& String::compareTo(string cmp2)
{
};
BTW, why does your compareTo return bool& ?
Also should avoid using namespace std; in any header files. see why-is-using-namespace-std-considered-a-bad-practice-in-c