Checking to see if a char pointer is null - Copy Constructor - c++

I am working on the following code
class base
{
private:
char* mycharpointer;
std::string mystring;
public:
base() : mycharpointer(NULL) {/*default constructor*/}
//Copy Constructor
base(const base& rhs){
if(mycharpointer != NULL) ---> Why is this condition true ?
{
mycharpointer = new char[ strlen(rhs.mycharpointer + 1)];
strcpy(this->mycharpointer,rhs.mycharpointer);
}
mystring = rhs.mystring;
}
base operator=(base& b)
{
if(this == &b)
return *this;
base temp(b);
temp.swap(*this);
return *this;
}
//Swap operation
void swap(base& lhs) {
std::swap(lhs.mycharpointer,this->mycharpointer);
std::swap(lhs.mystring,this->mystring);
}
//Destructor
virtual ~base(){
if(mycharpointer)
delete[] mycharpointer;
}
};
class der : public base
{
public:
char* mycharpointer_der;
std::string mystring_der;
foo* f;
public:
der():mycharpointer_der(NULL)
{
}
der(const der& rhs) : base(rhs)
{
if(mycharpointer_der)
{
mycharpointer_der = new char[ strlen(rhs.mycharpointer_der + 1)];
strcpy(this->mycharpointer_der,rhs.mycharpointer_der);
}
mystring_der = rhs.mystring_der;
f = new foo(*rhs.f);
}
der& operator=(der& d)
{
if(this == &d) //Make sure its not the same class
return *this;
base::operator= (d);
der temp(d);
temp.swap(*this);
return *this;
}
//Swap operation
void swap(der& lhs) {
std::swap(lhs.mycharpointer_der,this->mycharpointer_der);
std::swap(lhs.mystring_der,this->mystring_der);
}
virtual ~der(){
if(mycharpointer_der) //Necessary check as to make sure you are not deleting a NULL address otherwise exception thrown.
delete[] mycharpointer_der;
}
};
int main()
{
der d;
d.mycharpointer_der = "Hello World";
d.mystring_der = "Hello String";
der b;
b = d;
}
Now in the above code the copy assignment operator of d is called. which in return calls the copy assignment operator of the base class. In the copy assignment operator of the base class the copy constructor of the base class is called. My question is why is the condition
if(mycharpointer != NULL)
in the base class turning out as true ? Even when I have explicitly assigned it a NULL in the initialization list of the base class.

That check is ridiculous. At the point of construction, when we get into the body, mycharpointer is default-initialized and will contain some garbage value which may be 0 but likely won't be.
That said, what happens if rhs.mycharpointer is NULL? Then the strlen call would fail. That's the charpointer whose value you need to be checking:
base(const base& rhs)
{
if (rhs.mycharpointer) {
mycharpointer = new char[ strlen(rhs.mycharpointer) + 1 ];
// outside the parens ^^^^
strcpy(this->mycharpointer,rhs.mycharpointer);
}
else {
mycharpointer = NULL;
}
mystring = rhs.mystring;
}
Or since you're already using string, we could keep using string for mycharpointer too. That has the added benefit of us not even having to write the copy constructor which, as you can see, can be error prone:
base(const base& ) = default;

C++ compiler only make sure the global variable and static variables will be initialized, so In this case, the mycharpointer may actually points to some useless garbage(dangling pointer)
base(const base& rhs){
if(mycharpointer != NULL) ---> Why is this condition true ?
{
mycharpointer = new char[ strlen(rhs.mycharpointer + 1)];
strcpy(this->mycharpointer,rhs.mycharpointer);
}
mystring = rhs.mystring;
}
as mycharpointer actually point to the data allocated on the heap, so if you want to rellocate it, you need to release existing data first.
something like:
if ( mycharpointer) {
delete [] mycharpointer;
}

Apparently you're expecting the default constructor to run before the copy constructor does.
But it won't.

Related

Why copy constructor is called instead of move constructor with an rvalue initializer?

Here is the definition of SimpleString. It implements both copy constructor and move constructor.
struct SimpleString {
SimpleString(size_t max_size)
: max_size{ max_size }
, length{} {
if(max_size == 0) {
throw std::runtime_error{ "Max size must be at least 1." };
}
buffer = new char[max_size];
buffer[0] = 0;
}
~SimpleString() {
delete[] buffer;
}
SimpleString(const SimpleString& other)
: max_size{ other.max_size }
, buffer{ new char[other.max_size] }
, length{ other.length } {
puts("copy constructor");
std::strncpy(buffer, other.buffer, max_size);
}
SimpleString(SimpleString&& other) noexcept
: max_size(other.max_size)
, buffer(other.buffer)
, length(other.length) {
puts("move constructor");
other.length = 0;
other.buffer = nullptr;
other.max_size = 0;
}
void print(const char* tag) const {
printf("%s: %s", tag, buffer);
}
bool append_line(const char* x) {
const auto x_len = strlen(x);
if(x_len + length + 2 > max_size)
return false;
std::strncpy(buffer + length, x, max_size - length);
length += x_len;
buffer[length++] = '\n';
buffer[length] = 0;
return true;
}
size_t max_size;
char* buffer;
size_t length;
};
I implement + operator.
SimpleString operator+(const SimpleString& str_1, const SimpleString& str_2) noexcept {
SimpleString str_3{str_1}; // copy
str_3.append_line(str_2.buffer);
str_3.buffer[str_3.length-1]='\0';
return str_3;
}
Does this function return an rvalue?
In c++ primer(5th):
Functions that return a nonreference type, along with the arithmetic, relational, bitwise, and postfix increment/decrement operators, all yield rvalues.
So I think operator+ return an rvalue.
int main() {
SimpleString a{ 50 };
a.append_line("We apologise for the");
SimpleString b{ 50 };
b.append_line("Last message");
auto c = a+b; // copy constructor
c.print("c");
}
I thought it would call the move constructor and print move constructor, because a+b is an rvalue.
But the output is:
copy constructor
c: We apologise for the
Last message
Why the move constructor is not called?
Because of copy elision, or else return value optimization (RVO)
here!
It happens because the class type and the returned type are the same types.
So, the compiler instead of constructing the object str_3 in a place in memory, and afterward copy/move it, it (more optimally) construct it in-place!
I think you can enforce the usage of the move constructor by specifying:
return std::move(str_3)
I had the same question in the past, but for some reason they closed it...
here!

Assigment Operator for objects with user defined pointer members

I am trying to implement an operator= in C++ for an object which has as a member a pointer to a user defined type which also has dynamic memory allocated in it.
So given the code below, how would on implement a correct operator= for B? What I am after is how is the dynamic memory in A copied to the new B object?
Any help would be much appreciated.
Thank you
class A
{
int a;
int* b;
public:
A()
{
a = 1;
b = new int [20];
}
};
class B
{
A* a;
public:
B()
{
a = new A;
}
}
For starters you should define at least copy constructor, copy assignment operator and destructor for the class A. Then it is simple to define the copy assignment operator for the class B.
For example
#include <iostream>
#include <algorithm>
class A
{
static const size_t N = 20;
int a;
int* b;
public:
A()
{
a = 1;
b = new int [N]();
}
A( const A &a ) : a( a.a ), b( new int [N] )
{
std::copy( a.b, a.b + N, this->b );
}
A & operator =( const A &a )
{
if ( &a != this )
{
this->a = a.a;
int *p = new int[N];
std::copy( a.b, a.b + N, p );
delete [] this->b;
this->b = p;
}
return *this;
}
~A()
{
delete []b;
}
};
class B
{
A* a;
public:
B() : a( new A )
{
}
// copy constructor
~B()
{
delete a;
}
B & operator =( const B &b )
{
if ( this != &b )
{
*this->a = *b.a;
}
return *this;
}
};
int main()
{
B b1;
B b2;
b1 = b2;
}
Pay attention to that in the copy assignment operator at first created a new array before deleting the old one. This allows to keep the stable state of the assignable object if an exception will occur.
At very first: Have a look at the rule of three, it is an absolute must go in given case. Consider, too, the rule of five, while not mandatory, you'll leave out a great optimisation opportunity...
The destructor would now delete[] the array (leaving this part to you...), a copy constructor would then do exactly that: (deep) copy the data:
A::A(A const& other)
: a(other.a), b(new int[20]) // assuming you have a fixed size for those arrays;
// better: introduce a constant for to avoid magic
// numbers in code!
{
// you created a new array, but yet need to fill it with the others value
std::copy(other.b, other.b + 20, b);
}
OK, first step. Using the copy and swap idiom, the assignment operator gets pretty simple:
A& operator=(A other) // YES, no reference! This will invoke the copy (or move!)
// constructor of your class!
{
swap(*this, other); // you'll need to implement it yet!
return *this;
// at this point, the destructor of other will clean up data that was potentially
// contained in *this before...
}
Finally the move constructor:
A::A(A&& other)
: a(0), b(nullptr)
{
swap(*this, other);
// again swapping??? well, sure, you want the data from other to be contained
// in *this, and we want to leave other in some kind of valid state, which the
// nullptr is fine for (it's fine to delete[] a null pointer, so you don't even
// need to check in the destructor...)
}
And now up to you: class B analogously...
Side note: you get away a bit cheaper by use of a smart pointer (std::unique_ptr), it will allow you to default destructor and move constructor + assignment operator, solely copy constructor and assignment operator need to be implemented explicitly (std::unique_ptr is not copiable...).

Move assignment with base class and derived class

Below is a downsized implementation of a two classes I'm having trouble with.
code:
Here is the base class:
//header
class Script
{
public:
Script(const QString& path, int timeout=10000) :
mPath(path), mTimeout(timeout), script(new QProcess) {}
Script(Script&& s);
Script& operator=(Script&& s);
virtual ~Script();
protected:
QString mPath;
int mTimeout;
QProcess* script;
}
//source
Script::Script(Script&& s) :
mPath(s.mPath), mTimeout(s.Timeout), script(s.script)
{
s.script = nullptr;
}
Script& Script::operator=(Script&& s){
if(&s != this){
delete script;
script = s.script;
s.script = nullptr;
mPath = s.mPath;
mTimeout = s.mTimeout;
}
return *this;
}
Script::~Script() {
delete script;
script = nullptr;
}
From the code snippet above I derive the following class:
//header
class ConfigurationScript : public Script
{
public:
ConfigurationScript(const QString& path);
ConfigurationScript(ConfigurationScript&& s);
ConfigurationScript& operator=(ConfigurationScript&& s);
}
//source
ConfigurationScript::ConfigurationScript(const QString& path) :
Script(path) {}
ConfigurationScript::ConfigurationScript(ConfigurationScript&& s) :
Script(std::move(s)) {}
ConfiguratonScript& ConfigurationScript::operator=(ConfigurationScript&& s) {
if(&s != this){
delete script;
script = s.script;
s.script = nullptr;
mPath = s.mPath;
mTimeout = s.mTimeout;
}
return *this;
}
question:
The move assignment of ConfigurationScript contains duplicate code when you compare it to the move assignment of its base class Script. Can you call the assignment operator of the base class to overcome duplicate code?
For instance is something like this valid?
ConfigurationScript& ConfigurationScript::operator=(ConfigurationScript&& s) {
if(&s != this){
Script::operator=(s);
}
return *this;
}
The return type of Script::operator=(s) is Script, do I need to cast it to a ConfigurationScript?
If the above is valid, I fail to see how it works. Otherwise, is there a way to avoid code duplication?
Yes, it's valid, and you don't need to cast anything.
You're not even using the result of the base op= call, but you know that it is a Script& that refers to the current object. Since you already have a ConfigurationScript& that refers to the current object and has the needed type (i.e. *this), there is nothing more to do.
In fact, this is so natural that you can just let the compiler do it for you:
#include <iostream>
#include <utility>
struct Base
{
Base& operator=(Base&& other)
{
std::cout << "YOLO!\n";
return *this;
}
};
struct Derived : Base
{
/*
// Don't need this
Derived& operator=(Derived&& other)
{
Base::operator=(std::move(other));
return *this;
}*/
/*
// Or even this (though you may need to introduce it
// if you have some other user-declared stuff)
Derived& operator=(Derived&& other) = default;
*/
};
int main()
{
Derived d1, d2;
d2 = std::move(d1);
}
// Output: YOLO!
(live demo)
However I think you probably meant Script::operator=(std::move(s)) to get true movement rather than a copy.

std::map of user defined types crashes the program when retrieves a value

I have an Item class, whici has a copy constructor, an assignment operator, copy constructor and compare constructor. Thus, it can be used in a std::map (right?).
I need to use my Item class in a std::map< Item, Item >. However it doesn`t work and crashes the program, and I have no ideea why.
This is my Item class:
#include <iostream>
#include <string>
#include <vector>
#include <map>
enum DataType {
V_NULL,
V_INT,
V_FLOAT,
V_DOUBLE,
V_BOOL,
V_STR,
V_VECTOR,
V_MAP
};
// The Item can hold one of the types found in DataType enum
class Item {
// Everything public at first
public:
// Constructor: default is NULL
Item () {
m_type = V_NULL;
m_data = 0;
}
// Constructor:
// template, so you can specify the data in the Item
template<typename T>
Item(T actualDataInItem, DataType type) {
m_data = new Data<T>(actualDataInItem);
m_type = type;
}
// Destructor
~Item () {
delete m_data;
}
// Asignment operator:
const Item& operator= (const Item& other) {
// Check
if (this != &other) {
this->m_type = other.m_type;
// free the memory m_data points to !!!
delete m_data;
if (other.m_data != NULL)
m_data = other.m_data->clone();
}
return *this;
}
template<typename T>
const Item& operator= (const T& newData) {
delete m_data;
if (newData != NULL) {
m_data = new Data<T> (newData);
}
else {
m_data = NULL; // just for code reading
this->m_type = V_NULL;
}
return *this;
}
// Copy constructor:
Item(const Item& itemToCopy) {
this->m_type = itemToCopy.m_type;
this->m_data = itemToCopy.m_data->clone();
}
// Cast operator
template<typename T>
operator T () const {
// dynamic_cast m_data to point to "an Item of type T"
Data<T>* temp_data = dynamic_cast<Data<T>* > (m_data);
return temp_data->m_dataOfAnyType;
}
// for the map
bool operator< (const Item& other) const {
return this->m_data < other.m_data;
}
// All Data inherits DataBase, so that you can
// point to any Data<>
class DataBase {
public:
// Pure virtual method for cloning the current data
// Used when assignment operator is called with an Item argument
virtual DataBase* clone () = 0;
virtual ~DataBase () { }
};
// Data is the actual information carried in an Item.
// It can be anything like a string, int, vector<Events> etc
template<typename T>
class Data : public DataBase {
public:
T m_dataOfAnyType;
// Constructors:
Data ();
Data (T data) : m_dataOfAnyType(data) { }
virtual DataBase* clone () {
return new Data<T>(*this);
}
};
// members of Item
DataType m_type;
DataBase * m_data;
};
Any ideas?
Neither the copy constructor nor the assignment operator for
Item are correct. The copy constructor accesses the source
m_data even when it is a null pointer. Also, it would be
better to use initialization, rather than assignment (although
it doesn't make a significant difference here):
Item::Item( Item const& other )
: m_type( other.m_type )
, m_data( other.m_date == nullptr ? nullptr : other.m_data->clone() )
{
}
The assignment operator has several problems; there are several
different scenarios which will cause it to end up with
a dangling pointer. The most obvious is if the other pointer is
null; you don't set the target pointer to null. But also, if
cloning throws an exception, you will be left with an unusable
object (where even the destructor will cause undefined
behavior).
A good hint that something is wrong here is the fact that you
need to test for self assignment. If you need to test for self
assignment, it's almost certain that you assignment operator
isn't correct. The easiest way to correct it is to leverage off
the copy constructor:
Item& Item::operator=( Item const& other )
{
Item tmp;
swap( tmp );
return *this;
}
void swap( Item& other )
{
std::swap( m_type, other.m_type );
std::swap( m_data, other.m_data );
}
However, any solution which ensures that all operations which
can fail occur before any modifications of your object would
work, e.g.:
Item& Item::operator=( Item const& other )
{
DataBase* new_data = other.m_data == nullptr
? nullptr
: other.m_data->clone();
delete m_data;
m_type = other.m_type;
m_data = new_data;
return *this;
}
You'll also want to adopt this technique for the other
assignment operators (which are similarly broken).
You have at least one problem here
// Asignment operator:
const Item& operator= (const Item& other) {
// Check
if (this != &other) {
this->m_type = other.m_type;
// free the memory m_data points to !!!
delete m_data;
if (other.m_data != NULL)
m_data = other.m_data->clone();
}
return *this;
}
When you assign from an item where m_data is null you have a dangling pointer left and delete will be called another time on destruction or next assignement. To avoid this, you should add :
delete m_data;
m_data = NULL; // Assign there so that there is no dangling pointer even if clone() throws
if (other.m_data != NULL)
{
m_data = other.m_data->clone();
}
I do not know if it is the root of your problem but it can be.
The copy constructor has an error
// Copy constructor:
Item(const Item& itemToCopy) {
this->m_type = itemToCopy.m_type;
this->m_data = itemToCopy.m_data->clone();
}
You are assuming that itemToCopy.m_data is not NULL, but nothing guarantees this that I can see. This is better
// Copy constructor:
Item(const Item& itemToCopy) {
this->m_type = itemToCopy.m_type;
this->m_data = itemToCopy.m_data ? itemToCopy.m_data->clone() : NULL;
}

C++ : Two pointers (supposedly) to the same address. Changing contents of one of them don't change the contents of the other

I am new in C++ and arduino and I not understanding what is going on.
The problem is :
I have the variables below :
char *_array;
char _data[2];
When I do : _array = data; And then I change the contents of _data, like data[0] = 'C', data[1] = 'D'. The contents of _array don't change, and I need to do _array = _data again to apply the changes.
It seems that they don't point to the same address.
The code below is exemplifying this, the third print for me should be "3CD" instead of "3AB", but it is not what happens.
Could you help me please? I don't understand. Thank you!
#include <SoftwareSerial.h>
class Base {
public:
Base() {;};
void setArray(char* array) {_array = array;}
char *getArray() {return _array;}
private:
char *_array;
};
class A : public Base{
public:
A() : Base() {;};
A(char data1, char data2)
: Base()
{
setData(data1, data2);
setArray(_data);
}
void setData(char data1, char data2)
{
_data[0] = data1;
_data[1] = data2;
}
char *getData() {return _data;};
private:
char _data[2];
};
A a;
void setup()
{
Serial.begin(9600);
}
void loop()
{
a = A('A', 'B'); // This sets _data to "AB" and _array will point to _data
Serial.write('1');
Serial.write(a.getData()[0]);
Serial.write(a.getData()[1]); // This will print "1AB" (as expected)
a.setData('C', 'D'); // Here, _data changes to "CD" but _array no
Serial.write('2');
Serial.write(a.getData()[0]);
Serial.write(a.getData()[1]); // This will print "2CD" (as expected)
Serial.write('3');
Serial.write(a.getArray()[0]);
Serial.write(a.getArray()[1]); // This will print "3AB" (WHY?!?!?!)
Serial.write('4');
a.setArray(a.getData()); // If I call this function, _array changes to "CD"
Serial.write(a.getArray()[0]);
Serial.write(a.getArray()[1]); //This will print "4CD" (WHY I need to call setArray?)
delay(3000);
}
a = A('A', 'B'); // This sets _data to "AB" and _array will point to _data
In the above line, A('A', 'B') constructs a new A and establishes the internal _array. Then a = ... invokes the default assignment which just copies every member from source to destination. Now, a._array points to the char array of the temporary and that is how the invalid results come to be.
To avoid future errors,
implement an assignment operator
a copy constructor
and also let the default constructor initialize _array.
You need to at least write a copy constructor and an assignment operator for class A. The default copy will copy the pointer and not re-assign it to the new location.
e.g.
A(A const& rhs)
: Base(rhs)
{
memcpy(_data, rhs._data, sizeof(_data));
setArray(_data);
}
A& operator=(A const& rhs)
{
if (this != &rhs) {
static_cast<Base&>(*this) = rhs;
memcpy(_data, rhs._data, sizeof(_data));
setArray(_data);
}
return *this;
}