I am working with a class that is mostly working fine, but I am doing some functionality that I might be having a recursive function return a NULLpointer of the class type as a control, and so it might be assigning a NULL pointer to my class object so long story short:
Thing& Thing::operator=(Thing * _other){
if (_other == NULL){
*this = NULL; // compiler throws here
return *this;
}
// does other assignment work
return *this;
}
my compiler VS2010 throws that this is not an I-value. so how do I set the value to NULL, or is it even possible to set an item to NULL from inside?
EDIT: modified this to *this though for some reason now the program breaks with infinite calls to the assignment operator. no idea what is going on
You are trying to write a "nullable" class. Consider the "null" state to be one of the states an instance of Thing can be in, and don't convolute it with pointer semantics.
The general method would be to add a boolean flag to your class that keeps track of whether an instance is in null state or not. I would implement it like this:
class Thing
{
private:
bool m_null;
public:
void setnull() { m_null = true; }
bool isnull() const { return m_null; }
Thing() : m_null(true) {}
... // rest of class
};
And now the default assignment operator works fine.
You cannot directly set a value to the this pointer. Hence
this = NULL;
is semantically and syntactically wrong.
You can use exceptions to check if _other is NULL. For example:
class null_object_exception : public virtual exception {};
...
if (_other == NULL) throw null_object_exception();
To perform a NULL assignment:
Thing the_thing, other_thing;
try { the_thing = &other_thing; }
catch( const null_object_exception& e ) { the_thing = NULL; }
what are the member variables of Thing class?
if you want to show that the object is somehow without value or not intialized, you would better assign fileds 0 (for integers) and null(for pointers) etc, instead of assigning "this" which is constant.
Short answer, no, you can't assign to this in C++.
Longer answer; for your assignment operator to even be called, you'd have to have a construct like;
MyObject a;
a = NULL; // can change the content of `a` but not which object the name `a` refers to.
If you're thinking about this construct;
MyObject *a;
a = NULL;
your assignment operator won't even be called since it is an operator on the object, not the pointer. Assigning to the pointer a will work without you defining an assignment operator.
You CANNOT assign to this.
Also, you should take your arguments by const reference, so Thing& operator= (const Thing& other)
There's a great SO question in C++-faq tag about operator overloading, you can find it here
Related
Struct A
{
int* ptr;
int operator+=(const A& other)
{
// if(ptr == nullptr)
// { DoSomething(); }
// else { ...}
}
...
}
Is it possible to have a template operator+= (on a NON-template Class A) in order to resolve that if statement at compile time?
EDIT: I have a bunch of API's, all with the signature:
A funcX()
{
// lot of A's overloaded operators calls
return A;
}
Now, I need to use those API's with a new type, that shares a lot of members with A and add a new one (a smart pointer).
Since all the A funcX() return by value, I cannot derive my new type from A and call A funcX() with the derived type (slicing).
So my solution is to add a smart pointer to A, and a constructor in A that initializes that pointer.
So now I get to use all the API's, and when A is constructed with its new constructor (that initializes the pointer), I want all the operators to have a different behaviour than the existing one.
I was looking into some templates tricks to avoid the cost of checking the pointer inside each operator, although from the comments it doesn't seem possible to achieve it.
I am a beginner in C++, and this must be a really basic question. I understand & stands for referencing operation. For example, a = &b assigns the address of b to a. However, what does & in a declaration such as the following mean?
className& operator=(const className&);
Do the following make sense and what is the difference between the last line and the following?
className* operator=(const className*);
From the answers below, it seems --- as I understand it --- that the following is valid too. Is it? If it is, how is it different from the version with "&"?
className operator=(const className);
After reading the following answers and some more outside, I realized part of my original confusion stems from mixing up reference as in general computer science and reference type as in C++. Thank you all who answered my question. All the answers clarify my understanding to different degrees, even though I can only pick one as the accepted answer.
The token & has three distinct meanings in C++, two of which are inherited from C, and one of which is not.
It's the bitwise AND operator (unless overloaded).
It's the address operator, which acts on an lvalue to yield a pointer to it. (Unless overloaded.) This is what is happening in a = &b.
It denotes a reference type. const className& as a parameter is a const reference to an object of type className, so when the function is called, the argument will be passed by reference, but it won't be allowed to be modified by the function. The function you gave also returns a reference.
Assignment Operator
Understanding is best gained by example:
class A {
int x;
public:
A(int value) : x(value) {}
A& operator=(const A& from) { // Edit: added missing '=' in 'operator='
x = from.x;
return *this;
}
};
A m1(7);
A m2(9);
m2 = m1; /// <--- calls the function above, replaces m2.x with 7
Here, we defined the assignment operator. This special method is designed to provide assignment capability to objects.
The reason that it returns a reference to *this is so you can chain assignments without excessive memory copies:
A m3(11);
m3 = m1 = m2; /// <--- now, m3.x and m1.x both set to m2.x
Expanded as follows:
m3 = ( something )
where
(something) is a reference to the object m1
by result of call to m1.operator=(m2) method
such that
the returned reference is then passed into m3.operator(...)
Chaining lets you do this:
(m1=m2).function(); // calls m1.function after calling assignment operator
Libraries such as boost leverage this pattern (for a different type of chaining example, see the program options library in boost) and it can be useful when developing a domain specific 'language'.
If instead full objects were returned from operator=, the chained assignment would at a minimum involve multiple extra copies of the objects, wasting CPU cycles and memory. In many cases things would not work properly because of the copy.
Essentially, using a reference avoids a copy.
Note
In reality, (simplified explanation) a reference is just a fancy syntax for a C pointer.
In the common case, you can then write code with A.x instead of A->x.
Caution
Returning a pure reference from a method is often dangerous; newcomers can be tempted to return a reference to an object constructed locally inside the method on the stack, which depending on the object can lead to obscure bugs.
Your pointer example
It depends on what you return from the body of the method, but regardless, the following would instead return a pointer to some instance of className:
className* operator=(const className*);
This will compile and it even seems to work (if you return this from the method), but this does violate the Rule of Least Surprise, as it is likely anyone else attempting to use your code would not expect the assignment operator to return a pointer.
If you think about base types:
int x=1; int y=2; int z; z=y=x;
will never ever do anything other than return integers - so having operator= return the assigned to object is consistent)
It also doesn't let you do this:
(m1 = m2).something
It also allows you to pass NULL which is something assignment operators don't typically want to care about.
Instead of writing
blah& operator(const blah& x) { a = x.a ; return *this; }
You would need to write:
blah* operator(const blah* x) {
if (x) { a = x->a ; return this; }
else { /*handle null pointer*/
}
It means the function takes a reference to a const className and returns a reference to a className
Say you have a class like below:
class className
{
public:
className& operator=(const className& rhs)
{
this->a_ = rhs.a_;
this->b_ = rhs.b_;
return *this;
}
private:
std::string a_;
std::string b_;
};
You can use the assignment operator of the class as below:
className a;
className b;
className c;
c = b = a;
The above line is executed as:
c.operator=(b.operator=(a));
Now take another class that has the operator= defined using the second form:
class className2
{
public:
className2* operator=(const className2* rhs)
{
this->a_ = rhs->a_;
this->b_ = rhs->b_;
return this;
}
private:
std::string a_;
std::string b_;
};
You can use the assignment operator of the class as below:
className2 obj1;
className2 obj2;
className2 obj3;
obj2 = &obj1;
obj3 = &obj2;
The above lines are executed as:
obj2.operator=(&obj1);
obj3.operator=(&obj2);
However, such coding is not intuitive. You don't assign a pointer to an object. It is more intuitive to say:
className obj1;
className* objPtr = NULL;
objPtr = &obj1;
a = &b
Here, & gives address of b.
className& operator=(const className&);
Here, operator = will take const reference of variable of type className.
You can say in C++, & is polymorphic.
In short:
How do I define operator= for my class such that it compiles only if rhs is 0 (obj = 0)
but gives compilation error if rhs is non-0 value.
I know it is possible, forgot how.
Longer:
I have class C. I want to allow assignment obj = 0 for object of this class (which means, reset the object), but assignment from no other integer or pointer is defined. No conversion from integer or from pointer is defined other than obj=0.
C obj;
obj = 0; // reset object
Inside the operator=, I can do assert(rhs == 0), but that's not good enough.
I know it is possible
to define operator= such that
it gives compilation error if rhs is not 0. Forgot details.
Can anybody refill ?
Thanks
Use a pointer-to-member:
class foo
{
// Give it a meaningful name so that the error message is nice
struct rhs_must_be_zero {};
// The default operator= will still exist. If you want to
// disable it as well, make it private (and the copy constructor as well
// while we're at it).
foo(const foo&);
void operator=(const foo&);
public:
foo& operator=(int rhs_must_be_zero::*) { return *this; }
};
Since you can't access foo::rhs_must_be_zero, you cannot name a pointer to member from this class. The only pointer to member you can name is the null pointer, aka the literal zero.
Demo at http://ideone.com/bT02z
if I wanted to return "this" from a class member function as reference would this piece of code be correct ?
Record& operator=(const Record& that) {
m_name = that.m_name;
return *this;
}
Shouldn't i just use "return this" ?
Thanks for help :)
Yup, that's correct.
Return this wouldn't work since this is a pointer. (The reason it's a pointer and not a reference is because references weren't introduced into the language until after classes.)
In this specific case, if you're just going to assign the members anyway you shouldn't write a copy assignment operator; the default will do the same. When you manage some resource (and invoke the Rule of Three), you'd want to use the copy-and-swap idiom.
Your code is correct, but your comment shouldn't I just use "return this" is wrong (or, more accurately, the answer is "no, you shouldn't, and if you try, any compiler that works even halfway correctly compiler will stop you and give an error message.")
Given a class like:
class T {
void X() {}
void Y() const {}
};
In T::X, this will have the type T *const, and in T::Y, this will have the type T const *const. Either way, it's a pointer to T, not a reference to T. To get a reference to T (for returning or any other purpose) you need to use *this.
It may not matter for this specific case, but it is a good practice to have self assignment guard in the copy-assignment operator.
Record& operator=(const Record& that) {
if( &that != this ) {
m_name = that.m_name;
}
return *this;
}
This guards against statements like
Record r;
// do something with r
r = r; // this is protected
It would be important when the class is doing some resource (e.g. dynamically allocated memory) management.
I have a class that should hold a reference to some data, without owning that data (i.e. the actual data is guaranteed not to go out of scope). In particular, the class cannot make a copy – the data is easily several gigabytes in size.
Now, the usual implementation (I assume) is to have a reference to the data:
struct holder_ref {
type const& value;
holder_ref(type const& value) : value(value) { }
};
(Please note that the constness has absolutely no bearing on the problem).
Now, I absolutely need this class to be assignable (i.e. have a working operator =). I thought this was a fairly common problem but I can’t remember how (if ever) I’ve solved it before.
The problem is that a reference cannot be assigned and there’s simply no way around this. The only solution I’ve come up with uses placement new in place of the assignment operator:
// x = other_x; gets replaced with:
x.~T();
new (&x) T(other_x);
Now, this works and is standard compliant. But it sure is ugly. No – inacceptable.
So I’m searching for alternatives. One idea is to use pointers, but I’m unsure whether my constructor is actually guaranteed to work (and passing a pointer is impossible due to the interface I have to adhere to):
struct holder_ptr {
type const* value;
// Is this legal?
holder_ptr(type const& value = 0) : value(&value) { }
};
But I’d rather use a reference, if at all possible. Only – how to implement the assignment operator?
struct holder_ref {
type const& value;
holder_ref(type const& value = 0) : value(value) { }
holder_ref& operator =(holder_ref const& other) {
// Now what?!
return *this;
}
};
As a test case, consider the following code:
int main() {
int const TEST1 = 23;
int const TEST2 = 13;
int const TEST3 = 42;
std::vector<holder_ptr> hptr(1);
std::vector<holder_ref> href(2);
// Variant 1. Pointer.
hptr[0] = holder_ptr(TEST1);
// Variant 2. Placement new.
href[0].~holder_ref();
new (&href[0]) holder_ref(TEST2);
// Variant 3. ???
href[1] = holder_ref(TEST3);
assert(*hptr[0].value == TEST1); // Works (?)
assert(href[0].value == TEST2); // Works
assert(href[1].value == TEST3); // BOOM!
}
(Also, just to make this clear – the type we’re talking about is non-POD and I need a standard compliant solution.)
I don't see anything wrong with using a holder_ptr. It can be implemented something like so:
struct bad_holder : std::exception { };
struct holder_ptr {
holder_ptr() : value(0) { }
holder_ptr(type const& value) : value(&value) { }
type const& get() {
if (value == 0) throw bad_holder();
return *value;
}
private:
type const* value;
};
So long as you always assign to the pointer from a reference, you know that you have a valid object (that, or you ended up with a "null reference" previously, in which case you have other, bigger problems since you'll already have invoked undefined behavior).
With this solution, the interface is implemented entirely in terms of references, but under the hood a pointer is used so that the type is assignable. The use of references in the interface ensures there are none of the concerns that come with using pointers (namely, you never have to worry whether the pointer is null).
Edit: I've updated the example to allow for the holder to be default constructible.
I'd use the pointer holder. But if you are dead set against that, how about hiding your placement new operator=:
holder_ref& operator =(holder_ref const& other) {
new (this) holder_ref(other);
return *this;
}
Is a TR1 weak_ptr standard compliant enough?