简体   繁体   中英

Disallow taking pointer/reference to const to a temporary object in C++ (no C++0X)

I am faced with the following issue. Consider the following class:

//Will be similar to bost::reference_wrapper
template<class T>
class Ref {
public:
  explicit Ref(T& t) : m_ptr(&t) {}
private:
  T* m_ptr;
};

and this function returning a double

double fun() {return 1.0;}

If we now have

double x = 1.0;
const double xc = 1.0;

Ref<double> ref1(x); //OK
Ref<const double> refc1(cx); //OK

good so far, however:

//Ref<double> ref2( fun() ); //Fails as I want it to
Ref<const double> refc2( fun() ); //Works but I would like it not to

Is there a way to modify Ref (the way you prefer) but not the function fun, so that the last line returns a compile-time error? Please notice you can modify the constructor signature (as long as I am able to initialise the Ref as intended).

No, and your code can be broken even with a normal reference. Simply document the fact, that the passed object has to be persistent.

double *x = new double;
Ref<double> ref(*x);
delete x;    

You might not like the syntax to use it, but make the constructor take a pointer instead of a reference. You can't take even a const pointer to a temporary.

At least, not without smuggling it through another wrapper that hopefully makes the code Obviously Wrong(TM): template <typename T> T *reftoptr(T &t) { return &t; } template <typename T> T *reftoptr(T &t) { return &t; }

That said, if you're using this the way reference_wrapper is used, your users may actually want to capture temporaries. As long as the Ref object is also a temporary in the same full-expression as the temporary it captures, I think it's OK. So for example,

some_algorithm(iterator, anotherit, static_cast<Ref<const double> >(fun()));

Use a pointer argument to initialize your pointer member. Do not use a (const) reference for this - use a pointer to initialize a pointer.

I have had some problems with tracking references in the past, and while it's not directly related to your question, you might find these two threads interesting:

You can use a template. U& is deduced to double& , and that won't bind to rvalues.

template<class T>
class Ref {
public:
  template<typename U>
  explicit Ref(U& t, 
               typename boost::enable_if< 
                 boost::is_convertible<U, T&> 
               >::type * = 0) 
    : m_ptr(&t) {}
private:
  T* m_ptr;
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM