operator->
) in C++Goal. Understand how to implement operator->
correctly for wrappers and iterators, with modern C++ practices (const-correctness, exception guarantees, and clear ownership).
operator->
must returnThe result of operator->
must either be:
T*
or const T*
), oroperator->
(the resolution recurses until a pointer is produced).That design allows seamless member access like obj->member()
.
This example wraps a pointer to Triple
and controls access, but uses modern headers, int main()
, and const-correct overloads.
#include <iostream>
struct Triple {
int i, j, k;
void print() const {
std::cout << "\ni = " << i
<< ", j = " << j
<< ", k = " << k;
}
};
// Thin wrapper that optionally grants access to the underlying Triple
class TPtr {
bool access_;
Triple* ptr_; // educational: raw pointer with trivial lifetime rules
public:
TPtr(bool access, Triple* p) : access_(access), ptr_(p) {}
// const and non-const overloads; noexcept because it just returns a pointer
Triple* operator->() noexcept {
return access_ ? ptr_ : nullptr;
}
const Triple* operator->() const noexcept {
return access_ ? ptr_ : nullptr;
}
};
int main() {
Triple a{1,2,3}, b{4,5,6};
TPtr ta(false, &a), tb(true, &b);
if (ta.operator->() != nullptr) ta->print(); // no access → nullptr, guard if needed
if (tb.operator->() != nullptr) tb->print(); // access granted
}
operator->
for an iteratorCustom iterators usually provide both operator*
and operator->
. The latter should return a pointer to the element so member access is natural:
template <class T>
class SimpleIter {
T* p_ = nullptr;
public:
using value_type = T;
using reference = T&;
using pointer = T*;
using difference_type = std::ptrdiff_t;
using iterator_category = std::random_access_iterator_tag;
explicit SimpleIter(T* p) : p_(p) {}
reference operator*() const noexcept { return *p_; }
pointer operator->() const noexcept { return p_; }
// ... ++, --, +, -, ==, <, etc. as needed
};
operator->
should be noexcept
and fast; it typically just returns an address.std::unique_ptr<T>
or std::shared_ptr<T>
internally and return get()
from operator->
.nullptr
, throw, or an explicit status check.operator->
a simple gateway to the pointee; heavy policy checks belong elsewhere.This keeps the spirit of the original example while fixing headers and main
, and using nullptr
on denied access.
#include <iostream>
struct Triple {
int i, j, k;
void print() const {
std::cout << "\ni = " << i
<< ", j = " << j
<< ", k = " << k;
}
};
class TPtr {
bool access_;
Triple* ptr_;
public:
TPtr(bool access, Triple* p) : access_(access), ptr_(p) {}
Triple* operator->() noexcept { return access_ ? ptr_ : nullptr; }
const Triple* operator->() const noexcept { return access_ ? ptr_ : nullptr; }
};
int main() {
Triple a{1,2,3}, b{4,5,6};
TPtr ta(false, &a), tb(true, &b);
if (tb.operator->() != nullptr) tb->print();
}
vector class
so the operator implements an iterator.