I give the following example to illustrate my question:
class Abc
{
public:
int a;
int b;
int c;
};
class Def
{
public:
const Abc& abc_;
Def(const Abc& abc):abc_(abc) { }
Def& operator = (const Def& obj)
{
// this->abc_(obj.abc_);
// this->abc_ = obj.abc_;
}
};
Here I do not know how to define the copy assignment operator. Do you have any ideas? Thanks.
references cannot be assigned to. You need something that can. A pointer would work, but they're very abusable.
How about std::reference_wrapper?
#include <functional>
class Abc
{
public:
int a;
int b;
int c;
};
class Def
{
public:
std::reference_wrapper<const Abc> abc_;
Def(const Abc& abc):abc_(abc) { }
// rule of zero now supplies copy/moves for us
// use the reference
Abc const& get_abc() const {
return abc_.get();
}
};
A reference cannot be assigned. Due to this, one can only define it via placement new and copy construction:
Def& operator = (const Def& obj)
{
this->~Def(); // destroy
new (this) Def(obj); // copy construct in place
}
But it is really unnecesary. Just use a pointer.
Related
I have a class MyClass and another class that holds an array of MyClass, as follows:
class MyClass {
int a;
float b;
void SetInt(int value)
{
a = value;
}
void SetFloat(float value)
{
b = value;
}
}
class MyClassArray {
std::vector<MyClass> classList;
}
What is the easier way to create a new MyClass, insert an object in MyClassArray and call the methods to store value on it ?
Can I just create a temporary MyClass and insert it on the vector, calling the function in one statement ? Like:
classList.push_back(MyClass().SetInt(21));
classList.push_back(MyClass().SetFloat(1.23));
Is that valid ?
BTW: I need in vector a one object MyClass with 21 set on a and another one with 1.23 set on b, that´s why I´m not using initializers for a and b.
you can use chaining :
class MyClass {
int a;
float b;
public:
MyClass& Set(int value) { a = value; return *this; }
MyClass& Set(float value) { b = value; return *this; }
};
this enables thing like:
MyClass a;
a.Set(1).Set(1.5f);
and also:
vector<MyClass> vec;
vec.push_back(MyClass{}.Set(3));
Use your constructor
class MyClass {
int a;
float b;
}
class MyClassArray {
std::vector<MyClass> classList;
classList.push_back(MyClass(21,1.23));
}
You can use constructors for this. If you overload the constructor to take either an int or a float you would be able to set the value for both of the situations that you outlined.
class MyClass
{
int a;
float b;
MyClass(int i) : a(i) { }
MyClass(float f) : b(f) { }
}
this way you could add objects to the vector by doing this:
std::vector<MyClass> classList;
classList.push_back(MyClass(21));
and by doing this:
classList.push_back(MyClass(1.23));
If you really need to call a separate method you could do it like this:
class MyClass {
int a;
float b;
MyClass& SetInt(int value)
{
a = value;
return *this;
}
MyClass& SetFloat(float value)
{
b = value;
return *this;
}
}
Which will return a reference to the class. It is far better to do it using constructors though.
In a copy constructor of a struct/class, how can I avoid copying all the basic (int, double, etc.) members one by one if the intention is to copy a pointer successfully? Is it possible to extend the default copy constructor in this sense?
struct Type
{
int a;
double b;
bool c;
// ... a lot of basic members
int* p;
Type()
{
p = new int;
*p = 0;
}
Type (const Type& t)
{
// how to avoid copying these members one by one
this.a = t.a;
this.b = t.b;
this.c = t.c;
// but only add this portion
this.p = new int;
*this.p = *t.p;
}
};
Create an RAII wrapper for the int * data member that allows copying/moving.
struct DynInt
{
std::unique_ptr<int> p;
DynInt() : DynInt(0) {}
explicit DynInt(int i) : p(new int(i)) {}
DynInt(DynInt const &other) : p(new int(*other.p)) {}
DynInt& operator=(DynInt const& other)
{
*p = *other.p;
return *this;
}
DynInt(DynInt&&) = default;
DynInt& operator=(DynInt&&) = default;
// maybe define operator* to allow direct access to *p
};
Then declare your class as
struct Type
{
int a;
double b;
bool c;
// ... a lot of basic members
DynInt p;
};
Now, the implicitly generated copy constructor will do the right thing.
The following actually compiles and runs;
template <typename T>
class heap_ptr
{
public:
heap_ptr(T* p) : t(p) {}
heap_ptr(const heap_ptr&) = delete;
template<typename ... U> heap_ptr( U ... u )
{
t = new T(u...);
}
T* operator -> () { return t; }
// T& operator = (const T& o) { (*t)=o; return *t; }
operator T () { return *t; }
~heap_ptr() { delete t; }
private:
T* t;
};
struct A { int x,y; A(int x,int y):x(x),y(y){} };
void try_it()
{
heap_ptr<A> woop {8,11};
A a{5,3};
woop = a; // <- here
}
However, the marked assignment puts garbage in woop. Why does it compile, and
why do I get garbage in woop?
note: if I uncomment the assignment operator it works as expected, that's not the issue.
if I uncomment the assignment operator it works as expected, that's
not the issue
That's exactly the issue. Copy-assignment operator generated by default will copy the pointer, not the object behind it. And then the temporary object heap_ptr(a) is destroyed, deleting the data pointed to.
The problem is caused by the fact that by not implementing your operator= you are relying on the default one which will copy the pointer of the temporary object and then destroy it, leaving you with an invalid pointer once the copy is finished.
This is an instance of the set of problems that derive by not following the rule of three (five in C++11). When you can, you should follow the rule of zero, though.
You are trying to reimplement a smart pointer. Just use std::unique_ptr and it won't compile, like you expect:
struct A { int x,y; A(int x,int y):x(x),y(y){} };
void try_it()
{
std::unique_ptr<A> woop{ new A(8, 11) };
A a{5,3};
woop = a;
}
Live demo
Is there any possible way to overload operator* in such way that it's assigning and observing functions are defined apart?
class my_class
{
private:
int value;
public:
int& operator*(){return value;}
};
int main()
{
my_class obj;
int val = 56;
*obj = val; // assign
val = *obj; // observe, same operator* is called
}
Sort of -- you can have the operator* return an instance of another class, rather than returning a reference directly. The instance of the other class then defines both a conversion operator and an assignment operator.
(In your sample code, it looks like you've overloaded the multiplication operator when you meant to overload the dereferencing operator; I'll use the dereferencing operator below.)
For example:
class my_class
{
friend class my_class_ref;
public:
my_class_ref operator*() { return my_class_ref(this); }
private:
int value;
};
class my_class_ref
{
public:
operator int() { return owner->value; } // "observe"
my_class_ref& operator=(int new_value) { owner->value = new_value; return *this; } // "assign"
private:
my_class* owner;
my_class_ref(my_class* owner) { this->owner = owner; }
};
There are some caveats. For example, as my_class_ref is implemented with a pointer to its parent class, your code must be careful that my_class_ref always has a lifetime shorter than the lifetime of the corresponding my_class -- otherwise you will dereference an invalid pointer.
In practice, if you pretend that my_class_ref doesn't exist (i.e. never declare a variable with that class) it can work very well.
Write your class like so
class my_class
{
private:
int value;
public:
int operator*() const { // observing
return value;
}
int& operator*() { // assigning
return value;
}
};
Then these operators are dissambiguated by constness, so code like this is possible
int _tmain(int argc, _TCHAR* argv[])
{
my_class a;
*a = 1; // assigning
int k = *(const_cast<my_class const&>(a)); // observing
return 0;
}
I have a class like the following:
class A {
SuperHugeClass* s;
public:
A(){ s = new SuperHugeClass(); }
};
Because SuperHugeClass takes a lot of memory, I'm fine with the shallow copying provided by the default constructor and assignment operator. However, I also don't want to leak memory, so I need to delete s, but I have to be careful about it because otherwise I'll delete it more than once.
One way of doing this is by refcounting s as follows:
class A {
int* refcount;
SuperHugeClass* s;
public:
A(){
refcount = new int(1);
s = new SuperHugeClass();
}
A(const A& other) : refcount(other.refcount), s(other.s) {
(*refcount)++;
}
~A() {
(*refcount)--;
if (!(*refcount)) {
delete refcount;
delete s;
}
}
friend void swap(const A& a, const A& aa) {
std::swap(a.refcount, aa.refcount);
std::swap(a.s, aa.s);
}
A& operator=(A other) {
swap(*this, other);
return (*this);
}
};
This is the first time I've needed to do something like this, but it seems to me that this should be pretty standard and so there should be a 'canonical' solution. Are there any other ways of doing this? Thanks!
Use std::shared_ptr
class A {
std::shared_ptr<SuperHugeClass> s;
public:
A()
: s(new SuperHugeClass())
{
}
};
and thats it. Default generated copy constructor/assignment operator/destructor do just what you need.
Use std/boost::shared_ptr instead of your ref-counted pointer.