Get pointer to object from pointer to some member - c++

Suppose there's a structure
struct Thing {
int a;
bool b;
};
and I get a pointer to member b of that structure, say as parameter of some function:
void some_function (bool * ptr) {
Thing * thing = /* ?? */;
}
How do I get a pointer to the containing object? Most importantly: Without violating some rule in the standard, that is I want standard defined behaviour, not undefined nor implementation defined behaviour.
As side note: I know that this circumvents type safety.

If you are sure that the pointer is really pointing to the member b in the structure, like if someone did
Thing t;
some_function(&t.b);
Then you should be able to use the offsetof macro to get a pointer to the structure:
std::size_t offset = offsetof(Thing, b);
Thing* thing = reinterpret_cast<Thing*>(reinterpret_cast<char*>(ptr) - offset);
Note that if the pointer ptr doesn't actually point to the Thing::b member, then the above code will lead to undefined behavior if you use the pointer thing.

void some_function (bool * ptr) {
Thing * thing = (Thing*)(((char*)ptr) - offsetof(Thing,b));
}
I think there is no UB.

X* get_ptr(bool* b){
static typename std::aligned_storage<sizeof(X),alignof(X)>::type buffer;
X* p=static_cast<X*>(static_cast<void*>(&buffer));
ptrdiff_t const offset=static_cast<char*>(static_cast<void*>(&p->b))-static_cast<char*>(static_cast<void*>(&buffer));
return static_cast<X*>(static_cast<void*>(static_cast<char*>(static_cast<void*>(b))-offset));
}
First, we create some static storage that could hold an X. Then we get the address of the X object that could exist in the buffer, and the address of the b element of that object.
Casting back to char*, we can thus get the offset of the bool within the buffer, which we can then use to adjust a pointer to a real bool back to a pointer to the containing X.

My proposal is derived from the #Rod answer in Offset from member pointer without temporary instance, and the similar #0xbadf00d's one in Offset of pointer to member.
I started imagining a form of offset driving the implementation of a pointer to a class data member, later confirmed by the post in question and the tests i've made.
I'm not a C++ practitioner so sorry for the brevity.
#include <iostream>
#include <cstddef>
using namespace std;
struct Thing {
int a;
bool b;
};
template<class T, typename U>
std::ptrdiff_t member_offset(U T::* mem)
{
return
( &reinterpret_cast<const char&>(
reinterpret_cast<const T*>( 1 )->*mem )
- reinterpret_cast<const char*>( 1 ) );
}
template<class T, typename U>
T* get_T_from_data_member_pointer (U * ptr, U T::*pU) {
return reinterpret_cast<T*> (
reinterpret_cast<char*>(ptr)
- member_offset(pU));
}
int main()
{
Thing thing;
thing.b = false;
bool * ptr = &thing.b;
bool Thing::*pb = &Thing::b;
std::cout << "Thing object address accessed from Thing test object lvalue; value is: "
<< &thing << "!\n";
std::cout << "Thing object address derived from pointer to class member; value is: "
<< get_T_from_data_member_pointer(ptr, &Thing::b) << "!\n";
}

Related

std::shared_ptr<void> deleting when storing std::shared_ptr<unsigned int> [duplicate]

I found some code using std::shared_ptr to perform arbitrary cleanup at shutdown. At first I thought this code could not possibly work, but then I tried the following:
#include <memory>
#include <iostream>
#include <vector>
class test {
public:
test() {
std::cout << "Test created" << std::endl;
}
~test() {
std::cout << "Test destroyed" << std::endl;
}
};
int main() {
std::cout << "At begin of main.\ncreating std::vector<std::shared_ptr<void>>"
<< std::endl;
std::vector<std::shared_ptr<void>> v;
{
std::cout << "Creating test" << std::endl;
v.push_back( std::shared_ptr<test>( new test() ) );
std::cout << "Leaving scope" << std::endl;
}
std::cout << "Leaving main" << std::endl;
return 0;
}
This program gives the output:
At begin of main.
creating std::vector<std::shared_ptr<void>>
Creating test
Test created
Leaving scope
Leaving main
Test destroyed
I have some ideas on why this might work, that have to do with the internals of std::shared_ptrs as implemented for G++. Since these objects wrap the internal pointer together with the counter the cast from std::shared_ptr<test> to std::shared_ptr<void> is probably not hindering the call of the destructor. Is this assumption correct?
And of course the much more important question: Is this guaranteed to work by the standard, or might further changes to the internals of std::shared_ptr, other implementations actually break this code?
The trick is that std::shared_ptr performs type erasure. Basically, when a new shared_ptr is created it will store internally a deleter function (which can be given as argument to the constructor but if not present defaults to calling delete). When the shared_ptr is destroyed, it calls that stored function and that will call the deleter.
A simple sketch of the type erasure that is going on simplified with std::function, and avoiding all reference counting and other issues can be seen here:
template <typename T>
void delete_deleter( void * p ) {
delete static_cast<T*>(p);
}
template <typename T>
class my_unique_ptr {
std::function< void (void*) > deleter;
T * p;
template <typename U>
my_unique_ptr( U * p, std::function< void(void*) > deleter = &delete_deleter<U> )
: p(p), deleter(deleter)
{}
~my_unique_ptr() {
deleter( p );
}
};
int main() {
my_unique_ptr<void> p( new double ); // deleter == &delete_deleter<double>
}
// ~my_unique_ptr calls delete_deleter<double>(p)
When a shared_ptr is copied (or default constructed) from another the deleter is passed around, so that when you construct a shared_ptr<T> from a shared_ptr<U> the information on what destructor to call is also passed around in the deleter.
shared_ptr<T> logically[*] has (at least) two relevant data members:
a pointer to the object being managed
a pointer to the deleter function that will be used to destroy it.
The deleter function of your shared_ptr<Test>, given the way you constructed it, is the normal one for Test, which converts the pointer to Test* and deletes it.
When you push your shared_ptr<Test> into the vector of shared_ptr<void>, both of those are copied, although the first one is converted to void*.
So, when the vector element is destroyed taking the last reference with it, it passes the pointer to a deleter that destroys it correctly.
It's actually a little more complicated than this, because shared_ptr can take a deleter functor rather than just a function, so there might even be per-object data to be stored rather than just a function pointer. But for this case there is no such extra data, it would be sufficient just to store a pointer to an instantiation of a template function, with a template parameter that captures the type through which the pointer must be deleted.
[*] logically in the sense that it has access to them - they may not be members of the shared_ptr itself but instead of some management node that it points to.
It works because it uses type erasure.
Basically, when you build a shared_ptr, it passes one extra argument (that you can actually provide if you wish), which is the deleter functor.
This default functor accepts as argument a pointer to type you use in the shared_ptr, thus void here, casts it appropriately to the static type you used test here, and calls the destructor on this object.
Any sufficiently advanced science feels like magic, isn't it ?
The constructor shared_ptr<T>(Y *p) indeed seems to be calling shared_ptr<T>(Y *p, D d) where d is an automatically generated deleter for the object.
When this happens the type of the object Y is known, so the deleter for this shared_ptr object knows which destructor to call and this information is not lost when the pointer is the stored in a vector of shared_ptr<void>.
Indeed the specs require that for a receving shared_ptr<T> object to accept a shared_ptr<U> object it must be true that and U* must be implicitly convertible to a T* and this is certainly the case with T=void because any pointer can be converted to a void* implicitly. Nothing is said about the deleter that will be invalid so indeed the specs are mandating that this will work correctly.
Technically IIRC a shared_ptr<T> holds a pointer to an hidden object that contains the reference counter and a pointer to the actual object; by storing the deleter in this hidden structure it's possible to make this apparently magic feature working while still keeping shared_ptr<T> as big as a regular pointer (however dereferencing the pointer requires a double indirection
shared_ptr -> hidden_refcounted_object -> real_object
Test* is implicitly convertible to void*, therefore shared_ptr<Test> is implicitly convertible to shared_ptr<void>, from memory. This works because shared_ptr is designed to control destruction at run-time, not compile-time, they will internally use inheritance to call the appropriate destructor as it was at allocation time.
I am going to answer this question (2 years later) using a very simplistic implementation of shared_ptr that the user will understand.
Firstly I am going to a few side classes, shared_ptr_base, sp_counted_base sp_counted_impl, and checked_deleter the last of which is a template.
class sp_counted_base
{
public:
sp_counted_base() : refCount( 1 )
{
}
virtual ~sp_deleter_base() {};
virtual void destruct() = 0;
void incref(); // increases reference count
void decref(); // decreases refCount atomically and calls destruct if it hits zero
private:
long refCount; // in a real implementation use an atomic int
};
template< typename T > class sp_counted_impl : public sp_counted_base
{
public:
typedef function< void( T* ) > func_type;
void destruct()
{
func(ptr); // or is it (*func)(ptr); ?
delete this; // self-destructs after destroying its pointer
}
template< typename F >
sp_counted_impl( T* t, F f ) :
ptr( t ), func( f )
private:
T* ptr;
func_type func;
};
template< typename T > struct checked_deleter
{
public:
template< typename T > operator()( T* t )
{
size_t z = sizeof( T );
delete t;
}
};
class shared_ptr_base
{
private:
sp_counted_base * counter;
protected:
shared_ptr_base() : counter( 0 ) {}
explicit shared_ptr_base( sp_counter_base * c ) : counter( c ) {}
~shared_ptr_base()
{
if( counter )
counter->decref();
}
shared_ptr_base( shared_ptr_base const& other )
: counter( other.counter )
{
if( counter )
counter->addref();
}
shared_ptr_base& operator=( shared_ptr_base& const other )
{
shared_ptr_base temp( other );
std::swap( counter, temp.counter );
}
// other methods such as reset
};
Now I am going to create two "free" function called make_sp_counted_impl which will return a pointer to a newly created one.
template< typename T, typename F >
sp_counted_impl<T> * make_sp_counted_impl( T* ptr, F func )
{
try
{
return new sp_counted_impl( ptr, func );
}
catch( ... ) // in case the new above fails
{
func( ptr ); // we have to clean up the pointer now and rethrow
throw;
}
}
template< typename T >
sp_counted_impl<T> * make_sp_counted_impl( T* ptr )
{
return make_sp_counted_impl( ptr, checked_deleter<T>() );
}
Ok, these two functions are essential as to what will happen next when you create a shared_ptr through a templated function.
template< typename T >
class shared_ptr : public shared_ptr_base
{
public:
template < typename U >
explicit shared_ptr( U * ptr ) :
shared_ptr_base( make_sp_counted_impl( ptr ) )
{
}
// implement the rest of shared_ptr, e.g. operator*, operator->
};
Note what happens above if T is void and U is your "test" class. It will call make_sp_counted_impl() with a pointer to U, not a pointer to T. The management of the destruction is all done through here. The shared_ptr_base class manages the reference counting with regards to copying and assignment etc. The shared_ptr class itself manages the typesafe use of operator overloads (->, * etc).
Thus although you have a shared_ptr to void, underneath you are managing a pointer of the type you passed into new. Note that if you convert your pointer to a void* before putting it into the shared_ptr, it will fail to compile on the checked_delete so you are actually safe there too.

Why can I call a method that changes a member from a const method?

I'm not sure to understand why I can modify an object from a const method, look:
#include <iostream>
struct Foo {
int a = 0;
void change() {
a = 3;
}
};
struct Test {
Foo* f;
Test(): f{new Foo} {}
void test() const {
f->change();
}
};
int main()
{
Test t;
std::cout << "before: " << t.f->a << "\n";
t.test();
std::cout << "after: " << t.f->a << "\n";
}
Not only it compiles but it prints:
0
3
So I was able to modify the logical state of an object from a const method. Is that because I used a pointer?
The const applies to the pointer itself, f, not to what this pointer is pointing to. The type of f inside your const-qualified member function, Test::test(), is Foo* const (i.e., const pointer to Foo), not const Foo* (i.e., pointer to const Foo). That's why you can modify what the pointer is pointing to in spite of the const qualification of the member function.
Note that the following sample member function, Test::test2(), does fail to compile since it is const-qualified and tries to modify the pointer data member, f:
void Test::test2() const {
f = nullptr; // <-- error
}
No, you did not modify the logical state of an object:
f->change();
f, the object's class member, is as it's always been, here. Its value hasn't changed. It's not pointing to some other object now. It's still pointing to the same object it's always been pointing to.
What you did modify is the object to which f points to. Which is a different object.
Yes, you modified the logical state of the object. That's allowed, because const prohibits modifying the physical state.
The object t has one data member, f, whose type is "pointer to Foo". When the t object is created, it's f member points at an object of type Foo. After the call t.test() the f member still holds the same address, so it points at the same object of type Foo as it did before.
If test() had tried to change the value stored in f (i.e., the pointer) the const would have prevented it.
void Test::test() const { f = new Foo; } // error: `f` is const in this context

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?
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
}
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;

Casting from a Type* to Type and vice versa

Is it possible to cast from a predefined Type_pointer in c++ to its Type?
For example we defined a custom XType.
I want to do something like this, but I get an error:
XType* b;
XType a = (XType) b;
I want to pass the pointer itself to a function that only accept Type (not Type*)
You should dereference the pointer with the * operator:
struct Type {
Type(Type*) {}
};
void f(Type t) {
}
int main () {
Type a;
Type* b = &a;
// Q: how to invoke f() if I only have b?
// A: With the dereference operator
f(*b);
}
In addition to the #Robᵩ's proposal, you can change the function to accept the pointer.
Actually, if you plan to pass the pointer to other functions from within the given function, you must get the pointer (well, or a reference) as parameter, otherwise you'll get a copy of the original object as the parameter, so you'll be unable to retrieve the address of (i.e. pointer to) the original object.
If you'd like to spare the refactoring, you can do the reference trick:
void g(T* pt)
{
// ...
}
void f(T& rt) // was: void f(T rt)
{
cout << rt.x << endl; // no need to change, syntax of ref access
// is the same as value access
g(&rt); // here you get the pointer to the original t
}
T* t = new T();
f(t);

const correctness and return values - C++

Please consider the following code.
struct foo
{
};
template<typename T>
class test
{
public:
test() {}
const T& value() const
{
return f;
}
private:
T f;
};
int main()
{
const test<foo*> t;
foo* f = t.value();
return 0;
}
t is a const variable and value() is a constant member-function which returns const T&. AFAIK, a const type is not assignable to a non-const type. But how foo* f = t.value(); compiles well. How this is happening and how can I ensure value() can be only assigned to const foo*?
Edit
I found that, this is happening on when templates are used. Following code works as expected.
class test
{
public:
test() {}
const foo* value() const { return f; }
private:
foo* f;
};
int main()
{
const test t;
foo* f = t.value(); // error here
return 0;
}
Why the problem is happening when templates are used?
Because you have two levels of indirection - in your main function, that call to value returns a reference to a const pointer to a non-const foo.
This can safely be copied into non-const pointer to a non-const foo.
If you'd instantiated test with const foo *, it would be a different story.
const test<const foo*> t;
foo* f = t.value(); // error
const foo* f = t.value(); // fine
return 0;
Update
From the comment:
value() returns const T& which can
only be assigned to another const
type. But in this case, compiler is
safely allowing the conversion.
Const data can only be read. It cannot be written ("mutated"). But copying some data is a way of reading it, so it's okay. For example:
const int c = 5;
int n = c;
Here, I had some const data in c, and I copied the data into a non-const variable n. That's fine, it's just reading the data. The value in c has not been modified.
Now, suppose your foo had some data in it:
struct foo { int n; };
If I have a non-const pointer to one of those, I can modify the n value through the pointer. You asked your test template to store a pointer to a non-const foo, and then made a const instance of test. Only the pointer address is constant, therefore. No one can change the address stored in the pointer inside test, so it cannot be made to point to another object. However, the object it points to can have its contents modified.
Update 2:
When you made your non-template version of the example, you made a mistake. To get it right, you need to substitute foo * into each place where there's a T.
const T& value() const
Notice that you have a reference to a const T there. So the return value will be a reference to something const: a foo *. It's only the pointer address that can't be modified. The object it points to can have its contents modified.
In your second example, you got rid of the reference part, which changes the meaning and makes the const modifier apply to the object that the pointer points to, instead of applying to the pointer itself.
Use the following template specialization:
template<typename T>
class test<T*>
{
public:
test() {}
const T* value() const
{
return f;
}
private:
T* f;
};
After including this, g++ says:
d.cpp: In function ‘int main()’:
d.cpp:41: error: invalid conversion from ‘const foo*’ to ‘foo*’
There's nothing wrong in your code, having a const reference to a pointer only means that you can't modify the pointer, but the pointed-to object remains perfectly mutable. If inside your main function you try to change the address pointed to by the f member of t you'll see that you can't: encapsulation is perfectly preserved.
This is the same principle that makes the following code valid:
void foo(std::vector<int *> const & v)
{
*v[0] = 0; // op. [] returns const & to int *
}
People new to C++ are usually surprised by this behavior, because for them a const vector should not allow the modification of its elements. And in fact it doesn't, because the pointer stored in the vector does not change (it keeps pointing to the same address). It's the pointed-to object which is modified, but the vector does not care about that.
The only solution is to do as Amit says and provide a specialization of your class for T*.