What operators to implement with int members - c++

I have a class that has a few int and a const int member with a constructor defined.
class SomeContainer
{
public:
SomeContainer():
member1(0),
member2(staticMethod())
{}
private:
static int staticMethod();
int member1;
const int member2;
}
I need to create an assignment operator since I use this class in another class MainClass and code
MainClass* p1;
MainClass* p2
{
//...
*p1 = *p2 // fails since SomeContainer doesn't have copy assignment operator
}
Should this code be enough or am I missing anything?
{
SomeContainer(const SomeContainer& other): // copy ctor
member1(other.member1),
member2(other.member2)
{}
SomeContainer& operator=(const SomeContainer& other) // assignment operator
{
member1 = other.member1;
}
}
what about move ctor and move assignment? Should I need to implement those as well?

First of all if p1 and p2 are pointers then you can just assign them.
In case move constructor is not present then copy constructor will be used instead.
It remains for me hard to understand what is the logical meaning of allowing assignment on something that has constant non-static parts.

What you have written is sufficient.
When no move constructor exists then the copy constructor will be used instead, and there's really no purpose in move semantics here.

Just remove const from that member if you really need assignment

Related

Use assignment operators instead of an implicit constructor

In my program, I am trying to use the assignment operator= to assign an object of my class. I am specifically trying to call the assignment operator instead of an implicit constructor (thus the explicit keyword). When I try to compile, I get a C2440 Compiler Error:
class MyClass {
public:
explicit MyClass(double x = 0.) :
m_x(x) {
}
MyClass& operator = (const double& other) {
m_x = other;
/* do something special here */
return *this;
}
private:
double m_x;
};
int main()
{
MyClass my_class = 2.; // C2440
return 0;
}
I guess that the compiler fails trying to call the constructor implicitly (because of explicit). Does anyone have a fix?
MyClass my_class = 2.; is more or less equivalent to MyClass my_class(2.);, but, you marked the constructor as explicit, which prevents C++ from doing that automatically.
So, in the way you've written your code, you cannot really do what you want. You could explicitly call the constructor using:
MyClass my_class(2.); // Explcitly call your constructor
Or, as Ted Lyngmo mentioned in the comments, you can do:
MyClass my_class; // Call your constructor with default argument of 0
my_class = 2.; // then call your assignment operator

C++ Assignment operator for class that contains a unique pointer member variable

I understand that if I have a class with a smart unique pointer, it is not possible to assign that class to another instance, as a unique pointer cannot be copied. I understand that I could make the unique pointer a shared pointer and this would solve the problem. But what if I did not want to share ownership of the pointer? Is it possible to create an assignment operator that moves the unique pointer and copies the other variables?
I have read that you can use std::move to pass ownership.
#include <iostream>
#include <memory>
struct GraphStructure { };
class test {
int a;
std::vector<int> vector;
std::unique_ptr<GraphStructure> Graph_;
};
int main () {
test t1;
auto t2 = t1;
}
The default copy constructor of class test is deleted because of a member (graph_) not being copiable (if you still could copy in any meaningful way, e. g. by creating a deep copy of the graph member, you'd have to implement on your own copy constructor). In contrast, the default move constructor still exists (std::unique_ptr is movable). So what you can do is the following:
test t1;
auto t2 = std::move(t1);
Be aware, though, that t1 then won't hold any object any more (you moved the object, so you moved its contents to another one) and the object previously held by t2 is destroyed. If this is a meaningful state is up to you to decide...
Side note: What I wrote about copy and move constructors applies for copy and move assignment as well...
Fixing this the easy way
If GraphStructure is a class or struct without any virtual member functions, this is easy to do. We can write a function to duplicate the data inside a unique_ptr to create a new GraphStructure:
std::unique_ptr<GraphStructure> duplicate(std::unique_ptr<GraphStructure> const& ptr)
{
return std::make_unique<GraphStructure>(*ptr);
}
Once we have duplicate, we can use this class to write a copy constructor for test:
class test {
std::unique_ptr<GraphStructure> ptr;
std::vector<int> values;
public:
// this can be defaulted
test() = default;
// we use duplicate to create a copy constructor
test(const test& source)
: ptr(duplicate(source.ptr)))
, values(source.values)
{}
// we can use the default move constructor
test(test&&) = default;
test& operator=(test const& source) {
ptr = duplicate(source.ptr);
values = source.values;
return *this;
}
// we can use the default move assignment operator
test& operator=(test&&) = default;
};
What if GraphStructure has virtual methods?
In this case, add a virtual clone method to GraphStructure that returns a new std::unique_ptr<GraphStructure>:
class GraphStructure {
public:
// override this method in child classes
virtual std::unique_ptr<GraphStructure> clone() {
return std::make_unique<GraphStructure>(*this);
}
virtual ~GraphStructure() {}
};
Then, use .clone() in place of duplicate

Copy assignment operator defined in template being deleted by compiler

I'm familiar with the principle (for example, from this answer and this one) that when a class has a move constructor and/or move assignment operator, its default copy constructor and copy assignment operator are deleted. However, In the examples I've seen, this can be addressed by explicitly defining a new copy constructor and assignment operator.
In my particular case, I have a class which is derived by joint inheritance from a C-style struct and a template class. The copy and move assignment operators are explicitly defined in the template, whilst the copy and move constructors are explicitly defined in the class itself. In other words, everything is defined explicitly, though not all in the same place. Here is some example code:
typedef struct {
int n;
} myStruct;
template <typename T> class myTemplate
{
public:
// Default constructor
myTemplate<T>() : t_n(nullptr) {}
// Cannot create copy or move constructors in template, as cannot
// access the 'n' member directly
// Copy assignment operator
myTemplate<T> & operator=(const myTemplate<T> &source)
{
if (this != &source)
{
*t_n = *(source.t_n);
}
return *this;
}
//! Move assignment operator
myTemplate<T> & operator=(myTemplate<T> &&source)
{
if (this != &source)
{
*t_n = *(source.t_n);
*(source.t_n) = 0;
source.t_n = nullptr;
}
return *this;
}
T* t_n;
};
class myClass : public myStruct, public myTemplate<int>
{
public:
// Default constructor
myClass() : myTemplate<int>()
{
n = 0;
t_n = &n;
}
// Alternative constructor
myClass(const int &n_init) : myTemplate<int>()
{
n = n_init;
t_n = &n;
}
// Copy constructor
myClass(const myClass &source) : myTemplate<int>()
{
n = source.n;
t_n = &n;
}
// Move constructor
myClass(myClass &&source) : myTemplate<int>()
{
n = source.n;
t_n = &n;
source.n = 0;
source.t_n = nullptr;
}
};
int main()
{
myClass myObject(5);
myClass myOtherObject;
// Compilation error here:
myOtherObject = myObject;
return 1;
}
In Visual C++ and Intel C++ on Windows, this works exactly as I'd expect it to. On gcc 4.9.0 in Linux, however, I get the dreaded error message:
g++ -c -std=c++11 Main.cppMain.cpp: In function ‘int main()’:
Main.cpp:78:19: error: use of deleted function ‘myClass& myClass::operator=(const myClass&)’
myOtherObject = myObject;
^
Main.cpp:39:7: note: ‘myClass& myClass::operator=(const myClass&)’ is implicitly declared as deleted because ‘myClass’ declares a move constructor or move assignment operator
class myClass : public myStruct, public myTemplate<int>
Sure enough, the error goes away if I define an explicit copy assignment operator in the class itself, rather than in the template, but that's bothersome to do and undermines the advantage of using the template, since (a) my actual copy assignment operator is a lot bigger than the one shown here and (b) there are a large number of different classes that all share this template.
So, is this simply a bug in gcc 4.9.0, or is this in fact what the standard says should happen?
GCC is correct (and Clang and EDG agree).
myTemplate has a user-declared move constructor, therefore its copy assignment operator is deleted.
You've provided a copy constructor, but not copy assignment operator. Just declare a copy assignment operator for myTemplate and define it as defaulted. That takes one extra line of code.

Construction and initialization list : what the compiler do?

I have some questions about constructors in C++. For each question (from (1) to (4)) I would like to know if the behaviour is perfectly defined regarding to the standard.
A) The first one is about initialization of members :
class Class
{
public:
Class()
: _x(0)
, _y(_x)
, _z(_y) // <- (1) Can I initialize a member with other members ?
{
;
}
protected:
int _x;
int _y;
int _z;
};
B) What are the functions added to each class by the compiler ?
template<typename T> class Class
{
public:
template<typename T0>
Class(const Class<T0>& other)
{
std::cout<<"My copy constructor"<<std::endl;
_x = other._x;
}
template<typename T0 = T>
Class (const T0 var = 0)
{
std::cout<<"My normal constructor"<<std::endl;
_x = var;
}
public:
T _x;
};
// (2) Are
// Class(const Class<T>& other)
// AND
// inline Class<T>& operator=(const Class<T>& other)
// the only functions automatically added by the compiler ?
As an example, if I call :
Class<int> a;
Class<int> b(a); // <- Will not write "My copy constructor"
Class<double> c(a); // <- Will write "My copy constructor"
(3) Is this behaviour perfectly normal according to the standard ?
(4) Do I have the guarantee that an empty constructor is not automatically added and that Class<int> x; will write "My normal constructor" ?
Can I initialize a member with other members ?
Yes, as long as those other members have already been initialised; i.e. as long as their declarations come before the member being initialised.
Are [the copy constructor] and [the copy-assignment operator] the only functions automatically added by the compiler ?
It will also implicitly declare a destructor, which will destroy _x using its destructor.
In C++11, a move constructor (Class(Class&&)) and move-assignment operator (Class& operator=(Class&&)) are also implicitly declared, unless you declare a copy or move constructor, or a copy or move assignment operator.
Note that your constructor template is not a copy constructor, and the implicit one will be used instead:
Class<T1> t1;
Class<T1>(t1); // prints nothing
Class<T2>(t1); // prints "My copy constructor" (which is a lie)
Is this behaviour perfectly normal according to the standard ?
Yes, see chapter 12.
Do I have the guarantee that an empty constructor is not automatically added and that Class<int> x; will write "My normal constructor" ?
Yes, a default constructor will only be implicitly declared if you don't declare any constructors at all.

How delete a pointer of classes which has pointer members?

I mean, if i have some class like:
class A{
int* pi;
};
*A pa;
when i call delete pa, will pi be deleted?
You need to define a destructor to delete pi;. In addition you also need to define a copy constructor and assignment operator otherwise when an instance of A is copied two objects will be pointing to the same int, which will be deleted when one of the instances of A is destructed leaving the other instance of A with a dangling pointer.
For example:
class A
{
public:
// Constructor.
A(int a_value) : pi(new int(a_value)) {}
// Destructor.
~A() { delete pi; }
// Copy constructor.
A(const A& a_in): pi(new int(*a_in.pi)) {}
// Assignment operator.
A& operator=(const A& a_in)
{
if (this != &a_in)
{
*pi = *a_in.pi;
}
return *this;
}
private:
int* pi;
};
You should implement a destructor, ~A(), that takes care of cleaning up A's stuff. Afterwards, calling delete on a pointer of type A will clean-up everything.
You will need to write a destructor to delete all pointer type members. Something like:
class A
{
int *pi;
public:
~A(){delete pi;}
};
You will need to ensure that your constructor assigns a value to pi( at least a NULL). and like the answer from #hmjd, you will need to implement or hide the copy constructor and assignment operators. Look for the rule of three here:
http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29