For example, I have such a smart pointer:
template <typename T>
class SmartPointer
{
public:
....
T* operator & () { return m_p; }
private:
T* m_p;
}
void foo()
{
std::vector<SmartPointer<int> >vec;
vec.push_back(....);
vec.resize(.....);
......
}
Is this usage safe? I try it in MINGW4.4, It work ok....
In fact, those code is use work for COM, when I wanted to get a object, I need to do these
SmpartPointer<COMObj> spObj;
HRESULT hr = xxxxx->QueryInterface(&spObj);
then i wanted to store the pointer in a vector, so
std::vector<SmpartPointer<COMObj> >vec;
.....
In C++03, there is no explicit requirement that value types in containers do not overload unary operator&; however per 23.1p3 the objects stored are required to model CopyConstructible (20.1.3p1, Table 30). This in turn requires that the expression &t should yield a value of type T * that denotes the address of t. So overloaded unary operator& is permissible, but only if it has the "correct" return type and returns the correct value.
Your operator& is invalid; it should return SmartPointer<T> *.
In C++11 this was relaxed (through the use of std::addressof) so unary operator& can have any type and return any value.
In all versions of the standard, the type parameter of complex and valarray must not overload unary operator&; this is to allow them to be treated as contiguous storage.
Related
class NullClass{
public:
template<class T>
operator T*() const {return 0;}
};
I was reading Effective C++ and I came across this class, I implemented the class and it compiles. I have a few doubts over this:
It doesn't have a return type.
What is this operator.
and what it actually does.
That's the type conversion operator. It defines an implicit conversion between an instance of the class and the specified type (here T*). Its implicit return type is of course the same.
Here a NullClass instance, when prompted to convert to any pointer type, will yield the implicit conversion from 0 to said type, i.e. the null pointer for that type.
On a side note, conversion operators can be made explicit :
template<class T>
explicit operator T*() const {return 0;}
This avoid implicit conversions (which can be a subtle source of bugs), but permits the usage of static_cast.
It seems that Clang's UO_AddrOf unary operator is sensitive to the overloading of operator&.
For example, if we have
class notapointer {};
struct Bar
{
inline notapointer operator&()
{
return notapointer();
}
};
and E is a clang expression containing an instance of Bar, then
Expr* AddrOfE = Sema::BuildUnaryOp(0, loc, UO_AddrOf, E).get();
will return an expression of a notapointer instance instead of the address the object.
Is there a means to retrieve the actual address instead of following the operator& overload?
In a way, it behave like std::addressof.
According to 13.3.1.2/8, or better footnote-129 (emphasis mine):
[...] The process repeats until an operator-> function returns a value of non-class type.
I thought I knew how operator-> works (let me say, its recursive way based on the return type), but I see that I'm completely unaware about how it actually works (I mean, its return type).
When I found it, I wondered if one can really define and use something like a double operator->() for a generic struct S, for I've never used such an operator this way.
As an example, consider the code below:
struct S {
constexpr double operator->() noexcept {
return 3.14;
}
};
int main() {
static_assert(3.14 == S{}.operator->(), "!");
}
The syntax is quite ugly and I cannot see any use of such an operator or a similar one.
What is the real purpose of letting the programmers return a double or a float from this operator?
What could be a possible use for them?
The use for operator overloads is always questionable, and should be mostly consistent with the behavior of operators as seen with the intrinsic types.
Thus the overloading of the dereferencing operators -> and unary * should behave like they are used with pointers:
Citing from Operator overloading:
Operators for Pointer-like Types
For defining your own iterators or smart pointers, you have to overload the unary prefix dereference operator * and the binary infix pointer member access operator ->:
class my_ptr {
value_type& operator*();
const value_type& operator*() const;
value_type* operator->();
const value_type* operator->() const;
};
Note that these, too, will almost always need both a const and a non-const version. For the -> operator value_type must be of class (or struct or union) type, otherwise their implementation results in a compile-time error.1
The unary address-of operator should never be overloaded.
For operator->*() see this question. It's rarely used and thus rarely ever > overloaded. In fact, even iterators do not overload it.
Obviously you can do that overload with double as return type, but that's no different from possible (non-sensical, less useful) overloads for other standard operators like e.g.
#include <type_traits>
struct S {
constexpr double operator->() noexcept {
return 3.14;
}
void operator=(const S& rhs) {}
// ^^^^
void operator<(const S& rhs) {}
// ^^^^
};
Demo
int main() {
static_assert(3.14 == S{}.operator->(), "!");
}
Your cite
[...] The process repeats until an operator-> function returns a value of non-class type.
merely means that the dereferencing operation will stop as soon a non-class type is received as return type. Thus returning an intrinsic type will stop calling the dereference operation.
If a pointer is returned, or another type that overloads -> that operator will be called automatically upon the returned type.
1
Not so sure if this statement is actually valid, my and OPs example seems to prove otherwise.
What is the real purpose of letting the programmers return a double or a float from this operator?
What could be a possible use for them?
It works nicely with std::map::iterator. You can use:
std::map<int, int> m = { ... };
...
auto it = m.find(10);
if ( it != m.end() )
{
int val = iter->second;
}
What an operator is overloaded here?
operator T * ()
I know that the operator method has the following structure:
type operator operator-symbol ( parameter-list )
Assume we have the following code
template<typename T> class SmartPtr
{
public:
SmartPtr(T* data): member(data) {}
T* member;
T& operator * () { return *member; } //usage: *TObj
T*& operator () () { return member; } //usage: TObj()
operator T * () { return member; } //usage: ???
};
No compilation errors if you try it on the ideone. So what is going on here?
ADD: Am I right that static_cast<T*>(TObj) makes a call of the operator T *? I've tried it here.
That's a conversion operator, which allows the class to be converted to T*. Usage:
T * p = TObj;
It's probably a bad idea for a smart pointer to provide this, as it makes it easy to accidentally get a non-smart pointer. Standard smart pointers provide explicit conversion via a get() function instead, to prevent accidental conversions.
This operator is invoked when a SmartPtr object appears in an expression, but the compiler has no functions available to resolve the usage made thereof: if it's legal to use a T* where the SmartPtr appears, the operator T*() function is called to generate one. This means my_smartptr->my_T_member can work, as can f(T*); f(my_smart_ptr_to_T);. Similarly, iostreams have an operator bool() in C++11 (operator void*() in C++03 for reasons too tedious to bother with). It's kind of the opposite of an implicit constructor from a single parameter, where should the compiler not find a valid match using the parameter, it may try to construct an object using that parameter to use instead.
operator T * () { return member; }
it is a so-called conversion operator. It converts an object of type SmartPtr to type T *. Moreover it is an implicit conversion opertaor. So when the compiler awaits an object of type T * you can use instead an object of type SmartPtr.
You could make this conversion operator explicit if you would add keyword explicit. For example
explicit operator T * () { return member; }
C++11 provides the std::allocator_traits class as the standard way to use allocators. The static function std::allocator_traits::construct() takes a pointer to where the object should be constructed. The std::allocator_traits::allocate() static function, however, returns an allocator::pointer value, which only has to behave like a pointer but it is not necessarily one (in general, although std::allocator::pointer is required to be a pointer).
How is one supposed to use the allocation and construction static methods if, in general, they will work with incompatible types? Can they be used only if the pointer type is actually convertible to a normal plain pointer?
There are two techniques to do this depending on what you have at the moment.
If you have an lvalue expression, say the value field in a node, then you can use std::addressof like so:
allocator_traits<allocator_type>::construct(alloc, std::addressof(ptr->value), ...);
where ptr is an allocator_type::pointer.
However if you don't have a field to dereference and you want to convert an allocator_type::pointer to T*, there's a trick you need to implement first:
template <class T>
inline
T*
to_raw_pointer(T* p) noexcept
{
return p;
}
template <class Pointer>
inline
typename std::pointer_traits<Pointer>::element_type*
to_raw_pointer(Pointer p) noexcept
{
return p != nullptr ? ::to_raw_pointer(p.operator->())
: nullptr;
}
And now you can say:
allocator_traits<allocator_type>::construct(alloc, to_raw_pointer(ptr), ...);
Starting with C++20, there is std::to_address, proposed in P0653.