I got this copy constructor from a book and added the cout to compare the values:
Person::Person(const Person& c) {
m_pName = new string(*(c.m_pName));
m_Age = c.m_Age;
cout << m_pName << " " << &m_pName;
}
The cout will output 2 different addresses. The book I'm reading doesn't define what the m_pName is on its own without the &, it only says that &m_pName is the heap member address. What is the address returned without the & operator?
edit: Here is the class and constructor:
class Person() {
public:
Person(const string& name = 0);
Person(const Person& c);
private:
string* m_pName;
}
Person::Person(const string& name) {
m_pName = new string(name);
}
From the snippet you've provided it looks like m_pName is a pointer to string (to an std::string perhaps), so m_pName without an ampersand is the address of that string, just allocated.
Related
In the following code, when assignment operator is used, why is the copy constructor not being called or why is there no print corresponding to it?
#include <iostream>
#include <cstring>
using std::cout;
using std::endl;
class Person {
private:
char* name;
int age;
public:
Person() {
name = nullptr;
age = 10;
}
Person(const char* p_name, int p_age) {
name = new char[strlen(p_name) + 1];
strcpy(name, p_name);
age = p_age;
}
Person(Person const& p) {
cout << "Person copy constructor with " << p.name << endl;
name = new char[strlen(p.name) + 1];
strcpy(name, p.name);
age = p.age;
}
/*self assignment
The first is the self-assignment test. This check serves two purposes: it's an easy way to prevent us from running needless code on self-assignment,
and it protects us from subtle bugs (such as deleting the array only to try and copy it).
But in all other cases it merely serves to slow the program down, and act as noise in the code; self-assignment rarely occurs, so most of the time
this check is a waste. It would be better if the operator could work properly without it.*/
/*
Person& operator=(Person const& p) {
cout << "Person copy assignment with " << p.name << endl;
if(this != &p){
delete[] name;
name = nullptr;
name = new char[strlen(p.name) + 1];
strcpy(name, p.name);
age = p.age;
}
return *this;
}
*/
/*exception safety
If in the previous approach the memory allocation fails and throws an exception then the data in name is gone*/
/*
Person& operator=(Person const& p) {
cout << "Person copy assignment with " << p.name << endl;
char* temp_name = new char[strlen(p.name) + 1];
strcpy(temp_name, p.name);
delete[] name;
name = temp_name;
age = p.age;
return *this;
}
*/
//copy and swap idiom
/*
. Not only that, but this choice is critical in C++11, which is discussed later.
(On a general note, a remarkably useful guideline is as follows: if you're going to make a copy of something in a function,
let the compiler do it in the parameter list.‡)
*/
Person& operator=(Person p) {
cout << "Person copy assignment with " << p.name << endl;
swap(*this, p);
return *this;
}
/*
A swap function is a non-throwing function that swaps two objects of a class, member for member. We might be tempted to
use std::swap instead of providing our own, but this would be impossible; std::swap uses the copy-constructor and
copy-assignment operator within its implementation, and we'd ultimately be trying to define the assignment operator in terms of itself!
*/
friend void swap(Person &a, Person &b) {
using std::swap;
swap(a.name, b.name);
swap(a.age, b.age);
}
Person(Person&& other) {
swap(*this, other);
}
~Person() {
if(name)
cout << "Person destructor called for " << name << endl;
delete[] name;
}
};
int main() {
Person p("Ryan", 28);
Person a(p);
a = p;
cout << "Hello World" << endl;
return 0;
}
The output of the above code is:
Person copy constructor with Ryan
Person copy constructor with Ryan
Person copy assignment with Ryan
Person destructor called for Ryan
Hello World
Person destructor called for Ryan
Person destructor called for Ryan
why is the copy constructor not being called/there is no print corresponding to it.
Actually it's being called just fine. You can see right here in your own output:
Person copy constructor with Ryan
Person copy constructor with Ryan <--- This is it : )
Person copy assignment with Ryan
See here is the call site:
a = p;
and this is your assignment operator:
Person& operator=(Person p) {
cout << "Person copy assignment with " << p.name << endl;
swap(*this, p);
return *this;
}
So the copy constructor is being called here for who? and when? It's being called for this parameter p (with the RHS of the = from the call site as its parameter) right before entering the body of your operator= code. Hence in the output you see it as the line adjacently preceding this one:
Person copy assignment with Ryan
I have the following code:
template<class T = char>
class String
{
public:
// Default constructor
String()
: buffer(nullptr),
len(0)
{
cout << "Default constructor" << endl;
}
// Constructor
String(const char* s)
{
cout << "Constructor (const char*)" << endl;
//...
}
// Virtual destructor.
virtual ~String()
{
cout << "Destructor" << endl;
len = 0;
delete[] buffer;
}
// Copy constructor
String(const String& s)
{
cout << "Copy constructor" << endl;
buffer = new T[s.len];
std::copy(s.buffer, s.buffer + s.len, buffer);
len = s.len;
}
// Copy assignment operator (uses copy and swap idiom)
String& operator=(String s)
{
cout << "Copy assignment operator (copy and swap idiom)" << endl;
std::swap(buffer, s.buffer);
return *this;
}
// Move constructor
String(String&& s)
{
cout << "Move constructor" << endl;
}
// compound assignment (does not need to be a member,
// but often is, to modify the private members)
String& operator+=(const String& rhs)
{
cout << "operator+=" << endl;
//...
return *this; // return the result by reference
}
// friends defined inside class body are inline and are hidden from non-ADL lookup
// passing lhs by value helps optimize chained a + b + c
// otherwise, both parameters may be const references
friend String operator+(String lhs, const String& rhs)
{
cout << "operator+" << endl;
lhs += rhs; // reuse compound assignment
return lhs; // return the result by value (uses move constructor)
}
private:
T* buffer;
size_t len;
};
int main()
{
String<> s("Hello ");
String<> s2("World");
// call copy constructor first?
String<> s3 = s + s2;
return 0;
}
And the output is:
Constructor (const char*)
Constructor (const char*)
Copy constructor
operator+
operator+=
Move constructor
Destructor
My question is why is the copy constructor called immediately in:
String<> s3 = s + s2;
A value copy of s is taken by friend String operator+(String lhs, const String& rhs), essentially because s is not an anonymous temporary and is therefore not an appropriate candidate for move construction. Taking that value copy requires the copy constructor.
To my understanding, the copy constructor is called to receive the return value of the + operator.
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.
I have a class:
class Person{
public:
Person();
~Person();
string name;
int* age;
};
int main()
{
Person* personOne = new Person;
personOne->name = "Foo";
personOne->age = new int(10);
return 0;
}
How do I create another object of Person that copies all of personOne data? The age pointer needs to be pointing to a new int so whenever the age changes in personOne or personTwo, it doesn't affect each other.
There are two posibilites:
copy constructor + assignment operator
clone method
Code:
class Person{
public:
Person();
~Person();
Person (const Person& other) : name(other.name), age(new int(*(other.age)))
{
}
Person& operator = (const Person& other)
{
name = other.name;
delete age; //in case it was already allocated
age = new int(*(other.age))
return *this;
}
//alternatively
Person clone()
{
Person p;
p.name = name;
p.age = new int(age);
return p;
}
string name;
int* age;
};
Answer these before going forward:
do you really need an int pointer?
are you aware of smart pointers?
do you free all memory you allocate?
do you initialize all members in the constructor?
I'm fairly noobish at C++, but very comfortable with pointers, dereferencing, etc. I'm having a problem with my overload of the << operator for a class, in that it compiles fine but crashes when run. It feels like an infinite loop, but I'm not certain. Here's the code, and any help is appreciated.
#include <string>
#include <iostream>
using namespace std;
class Person
{
private:
string _name;
Person* _manager;
public:
Person(string name, Person *manager);
Person(string name);
friend ostream &operator<<(ostream &stream, Person &p);
};
Person::Person(string name, Person *manager)
{
_name = name;
_manager = manager;
}
Person::Person(string name)
{
_name = name;
}
ostream &operator<<(ostream &stream, Person &p)
{
Person* mgr = p._manager;
stream << p._name << std::endl;
stream << mgr->_name << std::endl;
return stream;
}
int main()
{
Person *pEmployee = new Person("John Doe Employee");
Person *pManager = new Person("John Doe Manager", pEmployee);
cout << *pEmployee;
cout << *pManager;
return 0;
}
In your constructor with just a single argument, you need to set _manager to NULL/0. Test for this in your operator<< and don't output mgr->name if it is NULL/0. As it stands, you are dereferencing an uninitialised pointer.
Person::Person(string name)
{
_name = name;
_manager = 0;
}
ostream &operator<<(ostream &stream, Person &p)
{
Person* mgr = p._manager;
stream << p._name << std::endl;
if (mgr)
stream << mgr->_name << std::endl;
return stream;
}
There are a number of other things you could do better, such as using const references on arguments and using the constructor initialiser list, but they wont be the cause of your problem. You should also address ownership issues with the manager object you pass in to the constructor to ensure it does not get double-deleted.
your _manager pointer is not initialized upon constructing the first Person instance, hence referencing p._manager in your operator << crashes.
Besides that, you have a memory leak since you call new but not delete.
Your implementation of operator<< does not check if the _manager member is valid. If there is no manager, you should make this explicit by setting the pointer to 0. Otherwise the pointer value is undefined and accessing it will crash your program.
(1) Your Person class should set _manager to 0 (null pointer) if none is supplied in the constructor:
Person::Person(string name) : _name(name), _manager(0)
{
}
(2) In your operator<<, check the pointer before dereferencing it:
if (mgr) {
stream << mgr->_name << std::endl;
}
Some hints for better code:
(1) Change your function arguments to accept const string& instead of string. This way, the string is not copied when calling the function/constructor, but passed as a constant reference.
(2) It is cleaner to let your operator<< accept a const reference for the Person as well, since it does not/should not modify the Person. This way, you can use the operator also in places where you have a constant Person.
Person::Person(string name)
{
_name = name;
}
Who is your manager?
Person::Person(string name) : _manager(NULL)
{
_name = name;
}
ostream &operator<<(ostream &stream, Person &p)
{
Person* mgr = p._manager;
stream << p._name << std::endl;
if (mgr != NULL) { stream << mgr->_name << std::endl; }
return stream;
}
Your Person instance *pEmployee does not have the _manager set. This may be a NULL pointer.