I'm trying to implement a tagged_ptr
class template in C++, but I'm not sure how to do it without invoking undefined behavior.
Here is what I currently have as an implementation:
template<typename T, size_t Alignment = alignof(T)>
class tagged_ptr
{
static_assert(
Alignment >= 2 && !(Alignment & (Alignment - 1)),
"Alignment template parameter must be a positive power of 2"
);
public:
using element_type = T;
using ptr_type = T*;
using tag_type = size_t;
static constexpr intptr_t const tag_mask = Alignment - 1;
static constexpr intptr_t const ptr_mask = ~tag_mask;
tagged_ptr(ptr_type ptr = nullptr, tag_type tag = 0) noexcept
{
set_ptr(ptr);
set_tag(tag);
}
void set_ptr(ptr_type ptr) noexcept
{
intptr_t tpval = reinterpret_cast<intptr_t>(ptr);
assert((tpval & tag_mask) == 0 && "ptr points to an improperly-aligned element");
tpval |= _ptr & tag_mask;
_ptr = tpval;
}
void set_tag(tag_type tag) noexcept
{
intptr_t tpval = tag;
assert((tpval & ptr_mask) == 0 && "tag is out of range");
tpval |= _ptr & ptr_mask;
_ptr = tpval;
}
ptr_type ptr() const noexcept { return reinterpret_cast<ptr_type>(_ptr & ptr_mask); }
tag_type tag() const noexcept { return static_cast<tag_type>(_ptr & tag_mask); }
protected:
intptr_t _ptr;
};
I also overload the bitwise-and, -or, and -xor operators to perform the appropriate operation on the internal _ptr
member variable with any type T
where std::is_integral<T>::value == true
.
Is this the correct way to do this? Is there anything that I'm doing wrong or that I should be careful of (besides the obvious danger of using unaligned pointers or out-of-range tag values)? If I use my class template, above, say, in the following manner, is there any undefined behavior?
int32_t x = 42;
int32_t y = 99;
tagged_ptr<int32_t> tp { &x, 1 };
std::cout << "ptr = " << tp.ptr() << "\n";
std::cout << "tag = " << tp.tag() << "\n";
tp.set_ptr(&y);
tp.set_tag( 2);
std::cout << "ptr = " << tp.ptr() << "\n";
std::cout << "tag = " << tp.tag() << "\n";
Otherwise, if the above implementation + example is no good, how could I implement tagged_ptr
, such that there would be no undefined behavior, or is it even possible?