Every non-static member function in a C++ class receives an invisible parameter: a pointer named this that refers to the object on which the function was invoked. While the compiler injects it automatical, knowing how and when to use it explicitly can make code clearer and safer.
What this Actually Is
Inside any non-static member function, this is a prvalue of type ClassName* const (or const ClassName* const in a const member function). It cannot be reseated, yet it is not a true variable—attempting to take its address yields an error.
Typical Scenarios Where this Helps
1. Disambiguating Names
When a parameter shadows a data member, prefixing the member with this-> removes ambiguity:
struct Counter {
int total;
void reset(int total) {
this->total = total; // left: data member, right: parameter
}
};
2. Returning the Current Object for Method Chaining
Returning *this by reference enables fluent interfaces:
class Logger {
std::string buf;
public:
Logger& append(std::string_view txt) {
buf += txt;
return *this; // allow: log.append("a").append("b");
}
void flush() { std::cout << buf << '\n'; }
};
3. Detecting Self-Assignment
Operator overloads often need to guard against a = a;:
class Buffer {
std::size_t len;
char* data;
public:
Buffer& operator=(const Buffer& rhs) {
if (this == &rhs) return *this; // self-assignment check
delete[] data;
len = rhs.len;
data = new char[len];
std::memcpy(data, rhs.data, len);
return *this;
}
};
4. Accessing Members in Lambda Captures
In C++20, lambdas inside member functions can capture *this by value to ensure the snapshot of the object is used, avoiding dangling references when the original object might move or be destroyed:
class Task {
int id;
public:
auto makeCallback() const {
return [*this] { std::cout << "Task " << id << " done\n"; };
}
};
Interaction with cv-Qualifiers and Ref-Qualifiers
The type of this reflects the function’s qualifiers:
void foo() const→const ClassName* constvoid foo() &→ClassName* const(lvalue object)void foo() &&→ClassName* const(rvalue object)
This distinction allows overloads based on the value category of the object:
class Matrix {
std::vector<double> m;
public:
Matrix clone() const& { return *this; } // copy
Matrix clone() && { return std::move(*this); } // move
};
Thread Safety Considerations
Each thread has its own call stack; therefore, the this pointer seen by a member function always refers to the object whose method that thread invoked. Shared objects stil require external synchronization—this itself does not provide any locking.
Corner Cases and Good Practices
- Never delete
thisinside a constructor or destructor; the object’s lifetime rules forbid it. - When overloading unary
&, remember that&objectwill call your operator, butthisremains the raw pointer supplied by the compiler. - In CRTP (Curious Recurring Template Pattern),
thisis cast to the derived type:static_cast<Derived*>(this)->impl();
template<typename Derived>
struct Base {
void interface() {
static_cast<Derived*>(this)->implementation();
}
};