Your proposed solution contains multiple instances of Undefined Behavior related to pointer arithmetic.
First (char*)(&s2) - (char*)(this)
is Undefined Behavior. This expression is governed by expr.add#5. Since the pointers aren't nullptr
and they don't point to elements in the same array, the behavior is undefined.
Second ((char*)(this) + offset)
is Undefined Behavior. This time the applicable paragraph is expr.add#4. Since (char*)(this)
isn't an element of an array, the only legal value for offset
would be 0. Any other value is Undefined Behavior.
But C++ already provides the tool necessary to solve the problem you are describing : pointer to data member. These pointers point to a member of a type instead of a member of an instance. It can be combined with a pointer to an instance (in this case a this
pointer) to get a normal object pointer.
Here is your example modified to use a pointer to data member (https://godbolt.org/z/161vT158q) :
#include <cstddef>
#include <iostream>
#include <string>
class Test {
std::string s1{"s1"}, s2{"s2"};
// A pointer to an `std::string` member of the type `Test`
using t_member_pointer = std::string Test::*;
// Points to `Test::s2`
t_member_pointer s_ptr = &Test::s2;
public:
std::string& get() {
// Combine the data member pointer with an instance to get an object
return (this->*s_ptr);
}
};
int main() {
Test test1;
Test test2 = test1;
std::cout << test2.get(); // note the copy
}
Notice that s_ptr
points to Test::s2
and not this->s2
. The value of a data member pointer is independent of any instance, it is compatible with any instance of that type. It therefore does not need to be corrected during copy or move, it will behave as expected if simply copied by value between instances.