Edit: Welp, I guess this was a terrible idea.
Is it possible to make a smart reference in C++ (for a specific class, since you can’t overload the . operator) with the same semantics as a normal C++ reference, but which is reseated when used in an STL container?
For example, if I have some int_ref class with the normal integer operators overloaded, and construction and assignment looks like this:
class int_ref{
int * p;
public:
int_ref(int * ip) : p(ip) {}
int_ref(const int_ref & other) : p(other.p) {
/* maybe some refcounting stuff here */
}
int_ref & operator = (const int_ref & other){
if (!p)
throw something_bad();
*p = *other.p;
return *this;
}
void reseat(const int_ref & other){
p = other.p;
}
}
Then I can’t use this with std::vector since it won’t reseat the references, and I don’t want this kind of thing:
std::vector<int_ref> vec;
int_ref five = new int(5);
vec.push_back(five);
vec.push_back(new int(1));
std::sort(vec.begin(), vec.end()); // the value of five is now 1
I can use rvalue references to make it play nice with the STL,
int_ref & operator=(int_ref && other){
reseat(other);
return *this;
}
But then a function that returns an int_ref would use the rvalue overload, and I’d get this:
int_ref make_number(){
return new int(10);
}
int_ref ref = new int(5);
int_ref other = ref;
other = make_number(); // instead of copying, as a reference would,
// other now points to something other than ref
Is there a way around this? Is this just a terrible idea in general?
One problem with even trying to do this is
operator&. For a reference, it gives you the address of the referand (since references have no address). For a element of a container, though, it’s expected to give you the address of the element (since those do have addresses).So, an element of a container cannot mimic reference semantics in this respect. If you overload
operator&to return the address of the referand, then for example the contiguous storage guarantee ofvectoris violated, since it says&v[n] == &v[0] + nfor all0 <= n < v.size()boost::addressof()was invented to work around this problem, so that you don’t have to use&to get the address of an object in generic code. But even the standard is too lazy to saystatic_cast<T*>(&static_cast<char&>(v[n]))rather than&v[n]. Even when you’re thinking of using it, it’s quite difficult to decide when you want the actual address of the object, and when you want the address that the author of the object thinks you want. It’s best just never to overload unaryoperator&. That means you’ll get a partial version of reference semantics, which potentially is confusing in its own way.