What does *this = NULL mean inside a method in a templated class? - c++

Inside a templated class, I found the expression, *this = NULL What does such an expression mean ?
The following is its definition:
TYPE** getPtr()
{
*this = NULL;
return &m_pPtr;
}
where m_pPtr is type TYPE* in the template class.
Assignment operator:
// Assignment operator.
TYPE* operator =(TYPE *pPtr) {
if (pPtr == m_pPtr)
return pPtr;
m_pPtr = pPtr;
return m_pPtr;
}
Vishnu.

It's difficult to say what the point of such a statement is without seeing the actual code.
But it will probably be invoking an overloaded assignment operator. e.g.:
#include <iostream>
class X {
public:
void operator=(void *) {
std::cout << "Here!\n";
}
void foo() {
*this = NULL;
}
};
int main() {
X x;
x.foo();
}

It's attempting to assign 0 to the current object. It will call something like
operator=(void *);
Another possibility (as far as I know) is that there is a constructor in the object which takes a void* or similar type. Then it would construct an object and then copy-assign that.
T :: T(void *); // construct with the void *
T :: T(const T &); // copy assignment

Related

Return unique_ptr member variable from proxy class with operator()

I would like to make a wrapper class (in this case a not null check, but it could be other checks).
Is there any way to extract member variable through operator() that would make it possible to move out the member variable. The use case is a std::unique_ptr<>
This is the use case
#include <memory>
struct S {
int x = 0;
S(int x): x(x) {}
};
template <typename Type>
class NotNull
{
public:
NotNull(Type value): m_value(std::move(value)) {}
operator Type&() // <--------------------------------- this is the question
{
assertIsNotNull();
return m_value;
}
typename std::pointer_traits<Type>::element_type *get() {
return m_value.get();
}
private:
void assertIsNotNull() {}
Type m_value;
};
And this is what needs to work
// Test code
int main() {
{
NotNull<S *> x {new S{10}};
auto y = x; // This works
delete y;
}
{
NotNull<std::shared_ptr<S>> x{std::make_shared<S>(10)};
auto y = x; // This works
}
{
NotNull<std::unique_ptr<S>> x{std::make_unique<S>(10)};
S* y = x.get(); // This does work, and needs to work as expected
// that is _not_ move the member
}
{
NotNull<std::unique_ptr<S>> x{std::make_unique<S>(10)};
auto y = std::move(x); // This copies the whole class
}
{
NotNull<std::unique_ptr<S>> x{std::make_unique<S>(10)};
std::unique_ptr<S> y = std::move(x); // <----------------- This does not work
}
}
The compiler seems to not understand that I want to convert to a unique_ptr inside of the std::move call.
error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = S; _Dp = std::default_delete<S>]'
57 | std::unique_ptr<S> y = std::move(x);
|
Compiler explorer link
Is it possible to use a class as a proxy for std::unique_ptr somehow and get this kind of syntax for moving out member variables.
PS. As you might have guessed I cannot rely on for example gsl::not_null, because this functionality does not exist there to my knowledge. DS.
The compiler understands that you want to convert to a unique_ptr& (i.e Type&) just fine. The problem arises when you assign the result of that conversion to your local unique_ptr object: since its an lvalue reference, the compiler tries to invoke the copy constructor (not the move constructor, which requires an rvalue reference), but since unique_ptr deleted its copy constructor, you get the error.
What you probably wanted to do in that line is to convert to a unique_ptr&& (i.e an rvalue reference). To do that, you can overload your conversion operator based on ref-qualifiers:
operator Type&() & // converts to lvalue ref if invoked on lvalue
{
assertIsNotNull();
return m_value;
}
operator Type&&() && // converts to rvalue ref if invoked on a temporary
{
assertIsNotNull();
return std::move(m_value);
}
This way, the conversion operator will convert to the same type of reference that it was invoked on (i.e lvalue of used from a normal variable, and rvalue if used on a temporary or moved object).
You can use reference qualifiers to make separate versions of a member function depending on whether the object is an lvalue or rvalue reference, like so:
#include <memory>
#include <iostream>
struct S {
int x = 0;
S(int x): x(x) {}
};
template <typename Type>
class NotNull
{
public:
NotNull(Type value): m_value(std::move(value)) {}
operator Type&()
{
assertIsNotNull();
return m_value;
}
auto get() &
{
std::cout << "lvalue \n";
return m_value.get();
}
auto get() &&
{
std::cout << "rvalue \n";
auto retval = m_value.get();
m_value.release();
return retval;
}
private:
void assertIsNotNull() {}
Type m_value;
};
int main()
{
{
NotNull<std::unique_ptr<S>> x{std::make_unique<S>(10)};
S* y = x.get(); // This does work, and needs to work as expected
// that is _not_ move the member
}
{
NotNull<std::unique_ptr<S>> x{std::make_unique<S>(10)};
std::unique_ptr<S> y = std::unique_ptr<S>(std::move(x).get()); // Is this what you want?
}
}

clarification on overloading the -> operator

I am trying to understand how overloading -> operator works. I have the following classes
class Message {
public:
Message(string message) :m_text(message) {}
void printText() {
cout << "text is " << m_text << endl;
}
string m_text;
};
class MessagePointerWrapper
{
public:
MessagePointerWrapper(string message) {
m_message = std::make_unique<Message>(message);
}
Message* operator->() {
return m_message.get();
}
std::unique_ptr<Message> m_message;
};
int main(int argc, char** argv)
{
MessagePointerWrapper messageWrapper = MessagePointerWrapper("Hello World");
messageWrapper.m_message->printText();
messageWrapper->m_text = "PQR";
messageWrapper.m_message->printText();
}
The MessageWrapper class's -> operator is overloaded to return a Message*.
So in the main method when I call messageWrapper-> what it returns is a Message*. Usually when I have a pointer, I need to use -> operator or the deference operator to access the object.
According to that logic, to access the m_text veriable of the Message object, the code should be written as below
(messageWrapper->) // this returns a pointer to Message. so to access the object, I should write as
(messageWrapper->)->m_text = "PQR"
or
*(messageWrapper->).m_Text = "PQR"
but this does not work that way and I need to call it as
messageWrapper->m_text = "PQR";
I don't understand the logic here. Can I get a clarification on this please.
==============
Some further notes :
In the main method I saw the below two methods do the same thing
messageWrapper.operator->()->m_text = "JKH";
messageWrapper->m_text = "JKH";
does it mean the operator -> works different from other operators where it means
messageWrapper-> is equivalent to (messageWrapper.operator->())->
and not messageWrapper.operator->() as is the case of other operators.
As the standard states, [over.ref]/1
An expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator->() exists and if the operator is selected as the best match function by the overload resolution mechanism
That means messageWrapper->m_text is a syntax sugar of (messageWrapper.operator->())->m_text. You can apply the latter style explicitly, but the former is more efficient. The overloaded operator-> makes it possible to use the class like raw pointers, and that's how smart pointers like std::unique_ptr and std::shared_ptr work.
The standard says :
13.5.6 Class member access
An expression x->m is interpreted as (x.operator->())->m for a class
object x of type T if T::operator->() exists and if the operator is
selected as the best match function by the overload resolution
mechanism
-> is a binary operator, it works using both arguments and will continue to resolve the left hand side so long as it is not a pointer.
That is, in the following code after the call to Wrapper2::operator ->() the compiler sees that the return type is a reference and calls Wrapper1::operator ->, only then does the call result in a pointer and 'm' is resolved against RealType.
struct RealType
{
int m;
};
class Wrapper1 {
RealType rt;
public:
RealType * operator ->() { return &rt; }
};
class Wrapper2 {
Wrapper1 w1;
public:
Wrapper1 & operator->() { return w1; }
};
int main()
{
Wrapper2 w;
w->m = 1;
};
The operator -> has to return a pointer, when it is used the return value is auto de-referenced, so you don't have to deference it by yourself adding a second ->

c++ using the = operator with objects

One operation that continues to confuse me in C++ is how operator= interacts with objects.
I'm not sure what exactly is occurring behind the scenes when executing a program such as this:
class ObjectType {
private:
int variable;
public:
ObjectType(int v) {
variable = v;
}
};
int main() {
ObjectType object1(10);
ObjectType object2(15);
object1 = object2;
return 0;
}
From my understanding, it makes all of the member variables in the first object equal to the corresponding member variables in the second object. In this case, the "variable" of object1 would now equal 15, but I'm not sure.
Any elaborations would be greatly appreciated, thank you.
When you type object1 = object2; Here it invokes = operator overloaded function, if operator overloading function for assignment operator is not
defined , then compiler does it for us by-default ,the compiler just does a member-wise copy from one object to another object.
Here is basic code :
class ObjectType {
private:
int variable;
public:
ObjectType(int v) {
variable = v;
}
void operator () (int n1){ /** () operator overloaded function if needed **/
variable = n1;
}
};
int main() {
ObjectType object1(10);//parameterized constructor will be called
ObjectType object2(15);
/** use case when () operator overloaded function will be called
ObjecType object1;
object1(10);// invokes () overloaded function
**/
object1 = object2;/** if = operator overloaded function is not defined then consider default one provided by compiler */
return 0;
}

Error invoking class method via function pointer on a wrapped object

I am coming from C background and new to CPP. I have a situation where I need to call a method on an object which will modify object. But on return from method, I need to restore object to its previous state. To achieve this I am using suffix, prefix wrapper technique illustrated by "Bjarne Stroustrup".
Along with this technique I am also trying to use function template and function pointer to generalize the methods that will be called on modified object.
template < class T >
class Call_proxy {
T* obj;
int ID;
public:
Call_proxy( T* pp ) : obj( pp ), ID( i ) {
}
~Call_proxy() {
obj->setID( ID );
}
T* operator ->() {
return obj;
}
};
template < class T >
class Proxy {
T* obj;
int ID;
public:
Proxy(T* pp) : obj(pp), ID(pp->getID()) { }
Call_proxy<T> operator ->() {
return Call_proxy<T>( obj, ID );
}
};
class X
{
int id;
public:
int getID();
void setID(int ID) { id = ID; }
void somefunction(int, int);
};
template<class X>
void doSomething(int nu, void(X::*fcn)(int, int))
{
Proxy<X> P(x);
P->setID(nu);
(P->*fcn)(nu, 1); //This call generates error on VS2010: Error 1 error C2296: '->*' : illegal, left operand has type 'Proxy<T>'
}
int main()
{
X x;
doSomething<X>(1, &X::somefunction);
}
Can you please help me understand VS2010 keep complaining about (P->*fcn)(nu, 1); construct?
From [expr.mptr.oper]:
The binary operator ->* binds its second operand, which shall be of type “pointer to member of T” to its
first operand, which shall be of type “pointer to U” where U is either T or a class of which T is an unambiguous
and accessible base class. The expression E1->*E2 is converted into the equivalent form (*(E1)).*E2.
Even though Proxy<T> has operator ->() implemented, it doesn't matter, because:
(P->*fcn)(nu, 1);
would not use operator ->. It is special according to the grammar. You can only invoke fcn on a pointer to X (or something derived from X).
void(X::*fcn)(int, int)
This is a pointer to a member function of the X class.
(P->*fcn)(nu, 1)
This is attempting to use P to execute the member function but P is of type Proxy<X> (i.e., it's not of type X and it's not a pointer).

"no match for ‘operator=’" error with g++

I have a class AP
template<typename T>
class AP : public std::auto_ptr<T>
{
typedef std::auto_ptr<T> Super;
public:
AP() : Super() { }
AP(T* t) : Super(t) { }
AP(AP<T>& o) : Super(o) { }
};
And a function to return it.
namespace AIR {
namespace Tests {
namespace
{
AP<A> CreateGraph()
{
AP<A> top(A::Create("xyz").release());
...
return top;
}
AP<A> top;
top = CreateGraph();
When I compile the code
AP<A> top;
top = CreateGraph();
I got this error message
no match for ‘operator=’ in ‘top = AIR::Tests::<unnamed>::CreateGraph()()’
I added this operator to the AP class, but it doesn't work.
AP<T>& operator=(AP<T>& o) { (*(Super*)this) = o; return *this; }
What's wrong with the class?
EDIT
top.reset(CreateGraph().release()) solved this issue.
CreateGraph() returns by value, thus a CreateGraph() function call is an rvalue.
Because the std::auto_ptr copy assignment operator takes its argument by non-const reference, the implicitly declared AP copy assignment operator takes its argument by non-const reference.
A non-const reference can only bind to an lvalue, hence the error.
As I explained in an answer to one of your previous questions, if you want to have std::auto_ptr-like copying (where the actual copy constructor takes its argument by non-const reference), you also need to implement something similar to std::auto_ptr_ref.
I explain how std::auto_ptr uses this helper class to allow copying of rvalues in the accepted answer to How could one implement std::auto_ptr's copy constructor?
Shouldn't it be?
AP<T>& operator=(const AP<T>& o)
What if you replace
AP<A> top;
top = CreateGraph();
to
AP<A> top(CreateGraph());