lightning_missile
lightning_missile

Reputation: 2992

Accessing the address of an object in a pointer handle

I am creating a pointer class, but I can't figure out how to return the value (address of the object pointed to) of the raw pointer handled by my class. My class is like this.

template<typename T>
class Ptr {
public:
    Ptr(T t) :p{&t} { }
T* operator->() { return p; }
T& operator*() { return *p; }
T& operator[](int i) { return p[i]; }
private:
T* p;
};

If I will do:

int x = 42;
Ptr<int> y = x;
std::cout << y; //should print the address (y.p).

I absolutely don't know what operator to overload so if I use "y" in any expression it will return the address of the object pointed to, just like what a raw pointer does. What should I do?

Upvotes: 0

Views: 91

Answers (2)

First off, your code has a bug. Your constructor is taking t by value, which means that p will store the address of the temporary t which will die at constructor exit (and the pointer will become dangling). You probably want this:

Ptr(T &t) : p{&t} {}

Even so, this means your pointer wrapper will be initialised by objects and not by pointers, which looks counter-intuitive. I'd change the constructor to accept a T*.

Second, you're asking how to get the "address of the raw pointer," but I assume you really want the "address stored in the raw pointer."

With this out of the way, let's turn to your question. There are several ways you can approach this.

  • One is to give your class an implicit conversion to T*, like this:

    operator T* () const
    { return p; }
    

    That way, an implicit conversion from Ptr<T> to T* will exist and the compiler will use it wherever necessary, but that may be a bit more than you want.

  • A more restricted version is to make the conversion explicit:

    explicit operator T* () const
    { return p; }
    

    Now you have to cast to the pointer explicitly:

    std::cout << static_cast<int*>(y);
    
  • You can follow the pattern used by std smart pointers and provide a get() function:

    T* get() const
    { return p; }
    
    std::cout << y.get();
    
  • Finally, if you only want this functionality for streaming, you can just overload operator<< for your class:

    template <class T, class Char, class Traits>
    std::basic_ostream<Char, Traits>& operator<< (std::basic_ostream<Char, Traits> &stream, const Ptr<T> &ptr)
    {
      return stream << ptr.operator->(); // or ptr.get(), if you implement it
    }
    

Upvotes: 4

molbdnilo
molbdnilo

Reputation: 66371

You should overload operator T*().

Note that the pointer you're storing is a pointer to the parameter and becomes invalid as soon as the constructor returns, so dereferencing it anywhere causes your program to be undefined.

You probably want

Ptr(T* t) : p{t} { }

and

Ptr<int> y = &x;

Upvotes: 2

Related Questions