assignment operator template and copy constructor in c++ - c++

so basically i m trying to use the assignment operator in way to allocate 2 vars :
S solutionCourante, bestSolution; //(S is a template class)
bestSolution = solutionCourante = solutionInitiale;
Here is the operator i'm dealing with :
template <class S, class T>
const Graphe<S,T> & Graphe<S,T>::operator = (const Graphe<S,T> & graphe)
{
this->lSommets = graphe.lSommets->copieListe(graphe.lSommets);
this->lAretes = graphe.lAretes->copieListe(graphe.lAretes);
return *this;
}
Here is my copy constructor :
template <class S, class T>
Graphe<S,T>::Graphe(const Graphe<S,T> & graphe)
{
*this = graphe;
}
(I know the constructor copy is a bit bad coded but works)
So at any time, i can see that "bestSolution" and "solutionCourante" are not NULL but empty, and i don't understand why because in my operator "monGraphe" is filled. So it seems like i m doing something wrong when returning the value, first time i m trying to do this operator.
According to :
const Graphe<S,T> & Graphe<S,T>::operator = (const Graphe<S,T> & graphe)
graphe is the item i want to copy and we got *this = graphe?

An assignment operator is supposed to assign a value to "this", not allocate a new one.
template <class S, class T>
Graphe<S,T> & Graphe<S,T>::operator = (const Graphe<S,T> & graphe)
{
lSommets = graphe.lSommets ? new PElement<Sommet<T>>(*graphe.lSommets) : nullptr;
lAretes = graphe.lAretes ? new PElement<Arete<S,T>>(*graphe.lAretes) : nullptr;
prochaineClef = graphe.prochaineClef;
return *this;
}
template <class S, class T>
Graphe<S,T>::Graphe(const Graphe<S,T> & graphe)
{
*this = graphe;
}
Generally speaking, you should not return something allocated on the heap with new, because any ownership information is lost. You should probably try to use smart pointers such as std::unique_ptr.

An answer was already posted, but uses a method of having the assignment operator doing most of the work.
Since you already coded the copy constructor, your assignment operator should be written using the copy/swap idiom: What is the copy-and-swap idiom?
What's usually done (if you want synergy between assignment operator and copy constructor) is to have the copy constructor do the bulk of the work, while the assignment operator utilizes the copy constructor (and destructor).
Here is your code using copy/swap:
#include <algorithm>
//...
template <class S, class T>
class Graphe
{
//...
friend void swap(Graphe<S,T>& lhs, Graphe<S,T>& rhs)
{
std::swap(lhs.lAretes, rhs.lAretes);
std::swap(lhs.lSommets, rhs.lSommets);
std::swap(lhs.prochaineClef, rhs.prochaineClef);
}
//...
};
//...
template <class S, class T>
Graphe<S,T>::Graphe(const Graphe<S,T> & graphe) :
{
lSommets = graphe.lSommets ? new PElement<Sommet<T>>(*graphe.lSommets) : nullptr;
lAretes = graphe.lAretes ? new PElement<Arete<S,T>>(*graphe.lAretes) : nullptr;
prochaineClef = graphe.prochaineClef;
}
template <class S, class T>
Graphe<S,T>& Graphe<S,T>::operator = (Graphe<S,T> graphe)
{
swap(*this, graphe);
return *this;
}
A function called swap was added to the template class that merely swaps all of the members between the left and right hand parameter. I emphasize all in the event that you didn't post all of your class members.
Assuming that your copy constructor is bug free, and your destructor is working and is bug-free, the code above will work correctly.
Edit: Made swap a friend function, as suggested by comments from T.C.

Related

Is there a method of determining where the = operator from class X is called within a preexisting project using overloaded operators through code?

Someone posed a question to me, they have a preexisting project, there is a variable that isnt behaving correctly and is causing memory issues, how can I help.
So I wanted to test a theory of mine where I created a basic templated class with a overloaded = operator to monitor any modification to the object.
template<class T>
class Tracker : public T
{
public:
Tracker() {};
T& operator=(const T& other);
};
template<class T>
inline T& Tracker<T>::operator=(const T& other)
{
std::cout << "Tracked Object Changed: " << std::endl;
T::operator=(other);
return *this;
}
So on my question, is there a way to determine where the overloaded = operator is called from (class/function/line number) to be able to log it to a text document for review later.

Implementing swap/copy functions: is there a better way?

These are how I implemented the swap and copy functions for my queue.
Is there a better way?
template <class T>
void Queue<T>::copy(Queue<T> const & other)
{
if(this == &other)
return;
if(m_size != 0)
this->clear();
this->m_cap = other.m_cap;
this->enqueue(other);
}
template <class T>
void Queue<T>::swap(Queue<T> const & other)
{
if(this == &other)
return;
std::swap(this->m_front, other.m_front);
std::swap(this->m_back, other.m_back);
std::swap(this->m_size, other.m_size);
std::swap(this->m_cap, other.m_cap);
}
Thank you:)
Instead of a copy method, you should instead implement a copy constructor. It would be strange for the copy constructor to be passed an instance of itself. If you insist on checking, you can use an assertion.
template <class T>
Queue<T>::Queue(Queue<T> const & other)
: m_cap(other.m_cap), m_size(0), m_front(), m_back()
{
assert(&other != this);
enqueue(other);
}
Your copy method is actually an assignment. It is more natural to implement an assignment operator. This can be accomplished by following the copy-swap idiom.
template <class T>
Queue<T> & Queue<T>::operator = (Queue<T> other)
{
swap(*this, other);
return *this;
}
There is also an idiomatic way to implement swap (taught to me by Mooing Duck a long time ago):
template <class T>
class Queue {
//...
friend void swap(Queue &a, Queue &b) {
using std::swap;
swap(a.m_front, b.m_front);
swap(a.m_back, b.m_back);
swap(a.m_size, b.m_size);
swap(a.m_cap, b.m_cap);
}
};
This way, you can use argument dependent lookup (ADL) to pick the type specific swap implementation if available. And now Queue itself has such an implementation, which is used by the assignment operator. But it can also be used in the case Queue is put inside an object that wants to implement swap for itself.

Unable to move temporary object into the *this object

While trying to create a Binary Search Tree (BST) using C++11 I hit a snag.
I can't extract a properly created BST out of the function where it is created.
The function reads data from a file (in this case just a number on each line) and builds a BST from those. The building part in the loop works correctly.
The problem is I can't get the temporary object moved where I want it to be.
Zooming in on the problem I think, see edit 3.
More context:
BST<T> is a class that derives publicly from std::unique_ptr<BSTknoop<T>>
BST<T> also inherits the constructors of unique_ptr<BSTknoop<T>> with
template<class T>
using BSTknoopptr=std::unique_ptr<BSTknoop<T>>; // alias template
and
using BSTknoopptr<T>::BSTknoopptr; // in the body of the BST<T> class declaration`
A BSTknoop<T> is a data structure with 3 fields
one T object to hold the node data
two BST<T> objects left and right (each child is a tree in its own right)
the goal is to move my newly created BST into the calling object. The idea is that in main you can call BST<int> tree; tree.lees(ifs); (with ifs an open input filestream) and tree holds the properly filled BST afterwards.
The function:
template<class T>
istream& BST<T>::lees(istream& is){
string lijn;
T knoopwaarde;
getline(is,lijn);
knoopwaarde = stoi(lijn);
BST<T> temptree(new BSTknoop<T>());
temptree->sl = knoopwaarde;
for(int i=1; i<DATA_SET_LENGTH ; i++){
getline(is,lijn);
knoopwaarde=stoi(lijn);
temptree.add(knoopwaarde);
cout<<temptree;
}
this->swap(temptree); /* This does not work */
/* *this = move(temptree); this does not work either*/
return is;
}
I have also tried to return a BST<T> from the function and moving that result in the main. That didn't work either.
The program crashes at runtime with an unknown signal.
Side note: I'm unsure as to why BST<T> temptree(new BSTknoop<T>()); works in regard to the templating. The construction works because BST<T> inherits the constructors for unique_ptr<BSTknoop<T>>
edit 1: the declaration of the BST<T> class:
template <class T>
class BST:public BSTknoopptr<T>{
using BSTknoopptr<T>::BSTknoopptr;
public:
friend istream& operator>>(istream& is, BST<T>& bb){
return bb.lees(is);
}
friend ostream& operator<<(ostream& os, const BST<T>& bb){
//return bb.schrijflevelorder(os);
return bb.schrijfKnoop(os);
}
void add(const T&);
ostream& schrijf(ostream&);
ostream& schrijfKnoop(ostream&) const;
int aantalSleutels() const;
istream& lees(istream&);
ostream& schrijflevelorder(ostream& os) const;
private:
};
the declaration of theBSTknoop<T> class:
template <class T>
class BSTknoop{
friend class BST<T>;
public:
BSTknoop() {}
explicit BSTknoop(T _sl) : sl(_sl) {}
private:
T sl;
BST<T> links,rechts;
};
edit 2: I've written a move constructor and move assignment operator. I've made sure to retain the default constructor as well using BST<T>()=default; I'm confused though: the BST class doesn't have any members for which I would have to implement my own move constr / operator.
However, BST has inherited from unique_ptr<BSTknoop<T>>so implicitly, it must hold a member of that type. Suppose I want to keep the inheritance, is there any neat way to make this work?
Is is also true that I can't (or perhaps shouldn't) implement a copy constr / operator as those are deleted for unique_ptr?
template<class T>
BST<T>::BST(BST<T>&& other){
*this = move(other);
}
template<class T>
BST<T>& BST<T>::operator=(BST<T>&& other){
cout<<"called move operator BST"<<endl;
(*this).BSTknoopptr<T>::operator=(move(other));
return *this;
}
edit 3: with my own move constr / operator, the temptree no longer gets filled properly. Below is my code for add which is used to build the tree. If I omit my own move constr / operator, then this works. What I need is an operation that works like this->get()->links = move(tmp).
types this->get()->links => BST<T>
tmp => BST<T>
How come this works? It does the operation I need, why can't I use something similar to do *this = move(temptree) by writing the operation myself.
template<class T>
void BST<T>::add(const T& value){
if(value <= this->get()->sl){
if(this->get()->links != nullptr){
this->get()->links.add(value);
}
else {
BST<T> tmp(new BSTknoop<T>(value));
this->get()->links = move(tmp);
}
}
else{
if(this->get()->rechts != nullptr){
this->get()->rechts.add(value);
}
else{
BST<T> tmp(new BSTknoop<T>(value));
this->get()->rechts = move(tmp);
}
}
}
Okay, I made the stupidest mistake. There is nothing wrong with the inheritance and accompanying move semantics. I used the DATA_SET_LENGTH preprocessor directive inside my istream& BST<T>::lees(istream& is) function. While my final dataset will hold a million items. My dataset for testing purposes only holds 12. I forgot to change the value of DATA_SET_LENGTH so stoi(lijn) crashed.
For anyone interested in the solution:
notes
You don't need to write much code to make this work.
It is possible to write BST<T>& operator=(BSTknoopptr<T>&&); yourself and it works. However even without explicitly writing your own it also works.
The BST class has no fields of pointer type so we don't get into trouble with unique_ptr not having a virtual destructor
Final question (perhaps someone can comment):
The inherited operator operator=(BSTknoopptr<T>&&), what does its signature look like in BST<T>? Mostly in regards to return type (if it's now a member of BST<T> what type does it return?).
** TLDR: why can I rely on the inherited move operator / move constructors of unique_ptr<BSTknoop<T>>? **
bst.h
#define DATA_SET_LENGTH 12
using namespace std;
template <class T>
class BST;
template <class T>
class BSTknoop;
template<class T>
using BSTknoopptr=std::unique_ptr<BSTknoop<T>>;
template <class T>
class BST:public BSTknoopptr<T>{
using BSTknoopptr<T>::BSTknoopptr;
public:
BST<T>& operator=(BST<T>&&) = default;
BST<T>(BST<T>&&) = default;
BST<T>()=default;
//BST<T>& operator=(BSTknoopptr<T>&&);
friend istream& operator>>(istream& is, BST<T>& bb){
return bb.lees(is);
}
friend ostream& operator<<(ostream& os, const BST<T>& bb){
//return bb.schrijflevelorder(os);
return bb.schrijfKnoop(os);
}
void add(const T&);
//schrijf schrijft uit in een vorm die min of meer menselijk leesbaar is
ostream& schrijf(ostream&);
ostream& schrijfKnoop(ostream&) const;
int aantalSleutels() const;
istream& lees(istream&);
//schrijflevelorder schrijft uit in een vorm die door lees(...) kan gelezen worden.
ostream& schrijflevelorder(ostream& os) const;
private:
};
template <class T>
class BSTknoop{
friend class BST<T>;
public:
BSTknoop() {}
explicit BSTknoop(T _sl) : sl(_sl) {}
private:
T sl;
BST<T> links,rechts;
};
//template<class T>
//BST<T>& BST<T>::operator=(BSTknoopptr<T>&& other){
// cout<<"called BST<T> move with BSTknoopptr r-value ref argument"<<endl;
// (*this).BSTknoopptr<T>::operator=(move(other));
// return *this;
//}
template<class T>
void BST<T>::add(const T& value){
if(value <= this->get()->sl){
if(this->get()->links != nullptr){
this->get()->links.add(value);
}
else {
//BSTknoopptr<T> tmp(new BSTknoop<T>(value)); if used with my own BST<T>& BST<T>::operator=(BSTknoopptr<T>&& other)
BST<T> tmp(new BSTknoop<T>(value));
this->get()->links = move(tmp);
}
}
else{
if(this->get()->rechts != nullptr){
this->get()->rechts.add(value);
}
else{
//BSTknoopptr<T> tmp(new BSTknoop<T>(value)); if used with my own BST<T>& BST<T>::operator=(BSTknoopptr<T>&& other)
BST<T> tmp(new BSTknoop<T>(value));
this->get()->rechts = move(tmp);
}
}
}
template<class T>
istream& BST<T>::lees(istream& is){
string lijn;
T knoopwaarde;
getline(is,lijn);
knoopwaarde = stoi(lijn);
BST<T> temptree(new BSTknoop<T>());
temptree->sl = knoopwaarde;
for(int i=1; i<DATA_SET_LENGTH ; i++){
getline(is,lijn);
knoopwaarde=stoi(lijn);
temptree.add(knoopwaarde);
cout<<temptree;
}
*this = move(temptree);
return is;
}
main.cpp
int main(){
ifstream ifs;
ifs.open("c.dat");
if(ifs.is_open()){
BST<int> tree;
tree.lees(ifs);
tree.schrijfKnoop(cout);
}
else {
cerr<<"failed to open file"<<endl;
return -1;
}
}

How to write Template class copy constructor

How to write copy constructor for a template class. So that if the template parameter is another user defined class it's copy constructor is also get called.
Following is my class
template <typename _TyV>
class Vertex {
public:
Vertex(_TyV in) : m_Label(in){ }
~Vertex() { }
bool operator < ( const Vertex & right) const {
return m_Label < right.m_Label;
}
bool operator == ( const Vertex & right ) const {
return m_Label == right.m_Label;
}
friend std::ostream& operator << (std::ostream& os, const Vertex& vertex) {
return os << vertex.m_Label;
}
_TyV getLabel() { return m_Label;}
private:
_TyV m_Label;
public:
VertexColor m_Color;
protected:
};
Either a) not at all, just rely on the compiler-provided default; or b) by just invoking the copy constructor of the member:
template <typename T> struct Foo
{
T var;
Foo(const Foo & rhs) : var(rhs.var) { }
};
The point is of course that the compiler-provided default copy constructor does precisely the same thing: it invokes the copy constructor of each member one by one. So for a class that's composed of clever member objects, the default copy constructor should be the best possible.
Assuming _TyV is a value type:
Vertex( Vertex const& src )
: m_Label( src.m_Label )
{}
Aren't those names within class instances reserved by the implementation, by the way?
The C++ standard reserves a set of names for use by C++ implementation and standard libraries [C++ standard 17.6.3.3 - Reserved names]. Those include but are not limited to:
Names containing a double underscore.
Names that begin with an underscore followed by an uppercase letter.
Names that begin with an underscore at the global namespace.
template <typename T>
class Vertex {
public:
//this is copy-constructor
Vertex(const Vertex<T> &other)
: m_Color(other.m_Color),m_Label(other.m_Label)
{
//..
}
//..
};
But I don't think you need to explicitly define the copy-constructor, unless the class have pointer member data and you want to make deep-copy of the objects. If you don't have pointer member data, then the default copy-constructor generated by the compiler would be enough.

Overloading = in C++

I'm trying to overload the assignment operator and would like to clear a few things up if that's ok.
I have a non member function, bool operator==( const MyClass& obj1, const myClass& obj2 ) defined oustide of my class.
I can't get at any of my private members for obvious reasons.
So what I think I need to do is to overload the assignment operator. And make assignments in the non member function.
With that said, I think I need to do the following:
use my functions and copy information using strcpy or strdup. I used strcpy.
go to the assignment operator, bool MyClass::operator=( const MyClass& obj1 );
Now we go to the function overloading (==) and assign obj2 to obj1.
I don't have a copy constructor, so I'm stuck with these:
class Class
{
private:
m_1;
m_2;
public:
..
};
void Class::Func1(char buff[]) const
{
strcpy( buff, m_1 );
return;
}
void Class::Func2(char buff[]) const
{
strcpy( buff, m_2 );
return;
}
bool Class& Class::operator=(const Class& obj)
{
if ( this != &obj ) // check for self assignment.
{
strcpy( m_1, obj.m_1 );
// do this for all other private members.
}
return *this;
}
bool operator== (const Class& obj1, const Class& obj2)
{
Class MyClass1, MyClass2;
MyClass1 = obj1;
MyClass2 = obj2;
MyClass2 = MyClass1;
// did this change anything?
// Microsofts debugger can not get this far.
return true;
}
So as you can probably tell, I'm completely lost in this overloading. Any tips? I do have a completed version overloading the same operator, only with ::, so my private members won't lose scope. I return my assignments as true and it works in main. Which is the example that I have in my book.
Will overloading the assignment operator and then preforming conversions in the operator== non member function work? Will I then be able to assign objects to each other in main after having completed that step?
You have a couple of obvious mistakes here and there is some confusion about what you are actually trying to achieve. Firstly, the assignment operator operator = is meant to copy the value from one instance to another. The return value of the assignment operator is almost always a non constant reference to the target of the copy, so that you can chain assignments:
Class & operator=(const Class &rhs)
{
// copy the members
return *this;
}
The comparison operator operator == is meant to perform a comparison of two instances. It returns a boolean true if they are equal:
boolean operator==(const Class &rhs) const
{
// check if they are equal
return something;
}
The confusion is why are you trying to copy values around, or maybe assign to the instances in the comparison operator?
Op== isn't the assignment operator. T& Op= (const T&) is.
bool operator==(const T& lhs, const T& rhs) is the operation to compare two Ts. It returns true if lhs is equal to rhs, for whatever definition of "equal" you want to code.
I am guessing that you want to compare the two objects. In that case, you can just overload the operator == in class "Class". You don't need assignment operator.
class Class
{
public:
Class(int i) : m_i(i){}
bool operator==( const Class& rhs)
{
return m_i == rhs.m_i;
}
private:
int m_i;
};
int main()
{
Class t1(10), t2(10);
bool b = (t1 == t2);
}
I am not sure whether I understood the question correctly. But if you trying to check the equality using a non-member function and can't do this only because you can't access the private members of the class, then you can declare the non-member function as a friend function and use it like this:
class Test
{
public:
Test(int i) : m_i(i){}
private:
int m_i;
friend bool operator==(Test& first, Test& second);
};
bool operator==(Test& first, Test& second)
{
return first.m_i == second.m_i;
}
int main()
{
Test t1(10), t2(10);
bool b = (t1 == t2);
}