Passing a non-const reference without a named object?

64 Views Asked by At

I have a class StreamRead that represents a file, that I'd like to pass to a constructor for other classes, like a Bitmap for instance. However, I cannot pass an unnamed temporary to Bitmap directly.


Bitmap::Bitmap(StreamRead & in) {
    // "in" cannot be const because StreamRead's reading operations
    // change the file position
    ...
}

int main() {
    Bitmap image(StreamRead("filename.png")); // illegal
}

I've found three ways to address this. The last one is the one I'm using because it's ergonomic, without using mutable, but I worry it may not be well defined in C++:

  • Always making named temporaries when making StreamRead objects
  • Making the file position member in StreamRead mutable and it's reading methods const
  • Giving StreamRead a method that returns a reference to itself, and chaining this call on the constructor.

So my code now looks like this:

StreamRead & StreamRead::pass() {
    return *this;
}

int main() {
    // legal, but is this well-defined?
    Bitmap image(StreamRead("filename.png").pass()); 
}

Can I depend on pass() always providing a valid reference? Or is the C++ compiler allowed to do funky stuff like destroy the StreamRead object immediately after it gets the reference to it, then call the constructor to Bitmap with the dangling reference?

1

There are 1 best solutions below

0
Nhat Nguyen On BEST ANSWER

I think you third approach should work fine, because the scope of the function parameters extend until the end of the function.

There are some other options for you to have the code work too. First you can declare the function parameter with const lvalue reference qualifier

Bitmap::Bitmap(const StreamRead & in) {}

Or you can do universal reference

template<typename T>
Bitmap::Bitmap(T&& in) {}

The reason you can't pass an unnamed temporary to the original function is because an unnamed temporary is a prvalue, and your paramter has lvalue reference qualifier, which means the reference's value can be changed. However, prvalues don't bind to a name so you can't really change it. You can change the value of a variable that has value 5, but you can't change the pure value 5.