Storing const reference to an object in class - c++

This sounds like a basic question, but I didn't find any comprehensive answer, so here it is. Consider this code snippet:
struct A {
const std::string& s;
A(const std::string& s) : s(s) {}
};
int main() {
A a("abc");
std::cout << a.s << std::endl;
return 0;
}
Demo.
As long as I understand, this is UB. String literal "abc" binds to const std::string& in constructor, creating a temporary string object. It is also bound to reference a.s, and it is destroyed once a is constructed. That is, const reference cannot chain lifetime prolongation. Dangling reference, boom. In this particular case I see no output at all on ideone.com, but anything could happen (remember velociraptors).
Ok, this one is clear. But what if this is actually our very intent: we want to store a const reference to an object? To an existing one, not to temporary? This sounds like a very natural task, yet I came up with only one (almost) natural solution to it. Accepting constructor's argument by std::reference_wrapper instead of by reference:
A(std::reference_wrapper<const std::string> r) : s(r) {}
Since std::reference_wrapper has deleted constructors from temporaries:
reference_wrapper( T&& x ) = delete;
this works just like expected. However, this is not quite elegant. Another approach I can think of is to accept forwarding reference T&& and to reject everything except const l-value strings with std::enable_if. This is even less elegant, I think.
Any other approaches?
UPD Another question: is this a legitimate usage of std::reference_wrapper, or may it be considered too specific?

I'd say the natural solution would be to do what reference_wrapper does: prevent construction from temporaries:
struct A {
const std::string& s;
A(const std::string& s) : s(s) {}
A(std::string&&) = delete;
};
You should also bear in mind that having a data member of reference type makes the class non-assignable (not even move assignment is possible) by default, and it's generally difficult to implement an assignment operator. You should consider storing a pointer instead of a reference:
struct A {
const std::string* s;
A(const std::string& s) : s(&s) {}
A(std::string&&) = delete;
};

There is a very simple class lvalue_ref provided in the lightweight and convenient "explicit" library by Andrzej KrzemieĊ„ski, which solves exactly this problem with a clear intention:
struct Processor
{
Big const& _big;
explicit Processor(lvalue_ref<const Big> b) : _big(b) {}
};
const Big b {};
Processor p {b}; // ok
Processor q {Big{}}; // error (temporary)

Related

C++ ownership of a function parameter

I wrote a function which has this form:
Result f( const IParameter& p);
My intention is that this signature will make it clear that the function is not taking ownership of the parameter p.
Problem is that Result will keep a reference to IParameter:
class Result
{
const IParameter& m_p;
public:
Result( const IParameter& p )
: m_p( p ){ }
};
But then it happened that somebody called the function like this:
const auto r = f(ConcreteParameter{});
Unfortunately the temporary can be bound to const reference, and this caused a crash.
Question is: how can I make it clear that the function is not supposed to be called with temporaries, and maybe have a nice compilation error when that happens? Is it actually wrong in this case to state that it is not taking the ownership, since is passing it to result that will be propagated outside the function call scope?
The easiest way to make it clear is to overload the function with an rvalue reference parameter. Those are prefered to const references for temporaries so they will be chosen instead. If you then delete said overload, you'll get a nice compiler error. For your code that would look like:
Result f( const IParameter&& ) = delete;
You can also do the same thing with Result to gaurd it as well and that would look like:
class Result
{
const IParameter& m_p;
public:
Result( const IParameter& p )
: m_p( p ){ }
Result( const IParameter&& ) = delete;
};
In general, if a function receives value by const&, it's expected, that the function will use the value, but won't hold it. You do hold the reference to value so you should probably change argument type to use shared_ptr (if the resource is mandatory) or weak_ptr (if resource is optional). Otherwise you'll run into that kind of problems from time to time, as no one reads documentation.
It's hard to tell. The best way would be to document that Result must not live longer than the IParameter used to construct it.
There are valid cases of temporaries sent as constructor that is perfectly valid. Think about this:
doSomethingWithResult(Result{SomeParameterType{}});
Deleting the constructor taking temporaries would prevent such valid code.
Also, deleting the rvalue constructor won't prevent all cases. Think about this:
auto make_result() -> Result {
SomeParameterType param;
return Result{param};
}
Even if the constructor with temporary is deleted, invalid code is still really easy to make. You will have to document the lifetime requirement of your parameters anyways.
So if you have to document such behavior anyways, I would opt for what the standard library does with string views:
int main() {
auto sv = std::string_view{std::string{"ub"}};
std::cout << "This is " << sv;
}
It won't prevent constructing string views from temporary strings since it can be useful, just like my first example.
You can manually remove a constructor accepting an IParameter&& rvalue from the overload set:
class Result
{
// ...
public:
Result( IParameter&& ) = delete; // No temporaries!
Result( const IParameter& p );
};
When client code tries to instantiate an object via
Result f(ConcreteParameter{}); // Error
the constructor taking a const-qualified reference is no match because of the missing const-ness, but the rvalue constructor exactly matches. As this one is = deleted, the compiler refuses to accept such an object creation.
Note that as pointed out in the comments, this can be circumvented with const-qualified temporaries, see #NathanOliver's answer for how to make sure this doesn't happen.
Also note that not everyone agrees that this is good practice, have a look here (at 15:20) for example.
I already voted #NathanOliver answer as the best one, because I really think it is given the information I provided. On the other hand I would like to share what I think is a better solution to solve this very specific scenario when the function is more complex than the one in my initial example.
The problem with the delete solution is that it grows exponentially with the number of parameters, assuming that all the parameters needs to stay alive after the function call ends and you want a compile time check that the user of your API is not trying to give the ownership of those parameters to the function:
void f(const A& a, const B& b)
{
// function body here
}
void f(const A& a, B&& b) = delete;
void f(A&& a, const B& b) = delete;
void f(A&& a, B&& b) = delete;
We need to delete all the possible combination, and this will be hard to maintain on the long run. So my proposed solution is to take advantage of the fact that the reference_wrapper constructor which wraps T by move is already deleted in STD, and then write this:
using AConstRef = reference_wrapper<const A>;
using BConstRef = reference_wrapper<const B>;
void f(AConstRef a, BConstRef b)
{
// function body here
}
In this way all the invalid overload will be automatically deleted. I do not see any drawback with this approach so far.

What is the most efficient way to set class variable using rvalue in c++?

I just started working with c++11 r-values. I read some tutorials, but I haven't found the answer.
What is the best way (the most efficient way) to set a class variable? Is below code correct or not? (let's assume std::string has defined move constructor and assignment operator).
class StringWrapper
{
private:
std::string str_;
public:
StringWrapper() : str_("") {}
void setString1(std::string&& str) {
str_ = std::move(str);
}
void setString2(const std::string& str) {
str_ = std::move(str);
}
// other possibility?
};
int main() {
std::string myText("text");
StringWrapper x1, x2;
x1.setString?("text"); // I guess here should be setString1
x2.setString?(myText); // I guess here should be setString2
}
I know that compiler can optimize my code and/or I can use overload functions. I'd like to only know what is the best way.
Herb Sutter's advice on this is to start with the standard C++98 approach:
void setString(const std::string& str) {
str_ = str;
}
And if you need to optimize for rvalues add an overload that takes an rvalue reference:
void setString(std::string&& str) noexcept {
str_ = std::move(str);
}
Note that most implementations of std::string use the small string optimization so that if your strings are small a move is the same as a copy anyway and you wouldn't get any benefit.
It is tempting to use pass-by-value and then move (as in Adam Hunyadi's answer) to avoid having to write multiple overloads. But Herb pointed out that it does not re-use any existing capacity of str_. If you call it multiple times with lvalues it will allocate a new string each time. If you have a const std::string& overload then it can re-use existing capacity and avoid allocations.
If you are really clever you can use a templated setter that uses perfect forwarding but to get it completely correct is actually quite complicated.
Compiler designers are clever folk. Use the crystal clear and therefore maintainable
void setString(const std::string& str) {
str_ = str;
}
and let the compiler worry about optimisations. Pretty please, with sugar on top.
Better still, don't masquerade code as being encapsulated. If you intend to provide such a method, then why not simply make str_ public? (Unless you intend to make other adjustments to your object if the member changes.)
Finally, why don't you like the default constructor of std::string? Ditch str_("").
The version with rvalue reference would not normally bind to an lvalue (in your case, mytext), you would have to move it, and therefore construct the object twice, leaving you with a dangerous object. A const lvalue reference should be slower when constructing from an rvalue, because it would do the same thing again: construct -> move -> move construct.
The compiler could possibly optimize the overhead away though.
Your best bet would actually be:
void setString(std::string str)
{
str_ = std::move(str);
}
The compiler here is suprisingly guaranteed to deduce the type of the argument and call the copy constructor for lvalues and the move constructor for rvalues.
Update:
Chris Dew pointed out that constructing and move assigning a string is actually more expensive than copy constructing. I am now convinced that using a const& argument is the better option. :D
You might probably use templatized setString and forwarding references:
class StringWrapper
{
private:
std::string str_;
public:
template<typename T>
void setString(T&& str) {
str_ = std::forward<T>(str);
}
};

Differentiating between const references to immutable vs. mutable objects

Is there any accepted way in C++ to differentiate between const references to immutable objects vs. mutable ones?
e.g.
class DataBuffer {
// ...
};
class Params {
// ...
};
class C {
public:
// Given references must be valid during instance lifetime.
C(const Params& immutableParameters, const DataBuffer& mutableDataBuffer) :
m_immutableParameters{immutableParameters},
m_mutableDataBuffer{mutableDataBuffer}
{
}
void processBuffer();
private:
const Params& m_immutableParameters;
const DataBuffer& m_mutableDataBuffer;
};
Here the semantic difference is given just in the names.
The problem is that const& instance variables only let you know the object won't be modified by the instance. There is no distinction in the interface whether or not they may be modified elsewhere, which I think is a useful feature to be able to describe in the interface.
Expressing this through the type-system would help make interfaces clearer, allow the compiler to catch errors (e.g. accidentally modifying parameters handed to a C instance, outside of the instance, in the example above), and possibly help with compiler optimizations.
Assuming that the answer is that the distinction isn't possible in C++, maybe there is something close which can be achieved with some templates magic?
Immutability is not part of the C++ type system. As such, you cannot differentiate between immutable objects and mutable ones. And even if you could, std::as_const will always ruin your attempt to do so.
If you are writing an interface that requires immutability of objects, the easiest way to handle this is to invoke the Fundamental Theorem of Software Engineering: "We can solve any problem by introducing an extra level of indirection." So make immutability part of the type system. For example (FYI: uses some small C++17 library stuff):
template<typename T>
class immutable
{
public:
template<typename ...Args>
immutable(std::in_place_t, Args &&...args) t(std::forward<Args>(args)...) {}
immutable() = default;
~immutable() = default;
immutable(const immutable &) = default;
//Not moveable.
immutable(immutable &&) = delete;
//Not assignable.
immutable operator=(const immutable &) = delete;
immutable operator=(immutable &&) = delete;
const T* operator->() const {return &t;}
const T& operator*() const {return t;}
private:
const T t;
};
With this type, the internal T will be immutable regardless of how the user declares their immutable<T>. Your C class should now take an immutable<Params> by const&. And since immutable<T> cannot be constructed from a copy or move of an existing T, the user is forced to use immutable<Params> whenever they want to pass that as a parameter.
Of course, your biggest danger is that they'll pass a temporary. But that was a problem you already needed to solve.
I don't know the reason, but here's how you can do it:
struct C {
template<typename T, typename T2>
C(T&&, const T2&&) = delete;
C(const Params&, const DataBuffer&) { /*...*/ }
};
By declaring a constructor that takes any argument by non-const reference, it will always be a better match than the constructor taking const&, as a cv-qualifier doesn't have to be added.
The const& constructor is a better match when passing a const parameters, as the cv-qualifier doesn't have to be removed.
DataBuffer db;
const Params cp;
C c{ cp, db }; // ok, second constructor call is chosen
Params p;
C c2{ p, db }; // error, constructor is deleted
Due note that, as #IgorTandetnik said, you can break your requirement easily:
Params pa;
const Params& ref_pa = pa;
C c3{ ref_pa, db }; // ok, but shouldn't compile.
As previous answers, C++ doesn't have the concept of "immutable". #Rakete1111 gave you the answer I would have used. However, Visual Studio will put global const variable in .rdata segment, where other variables will go to .data. The .rdata segment will generate a fault when trying to write.
If you need a run time test whether an object is read only, use a signal handler, like this:
#include <csignal>
const int l_ci = 42;
int l_i = 43;
class AV {};
void segv_handler(int signal) {
throw AV{};
}
template <typename T>
bool is_mutable(const T& t)
{
T* pt = const_cast<int*>(&t);
try {
*pt = T();
}
catch (AV av) {
return false;
}
return true;
}
void test_const()
{
auto prev_handler = std::signal(SIGSEGV, segv_handler);
is_mutable(l_i);
is_mutable(l_ci);
}
What you need is not a const reference, but a const object. Value semantics solve your problem. Nobody can modify a const object. While a reference is only const where it is marked const, because the referenced object may not be const. Take that for example :
int a;
int const& b = a;
// b = 4; <-- not compiling, the reference is const
Above, a is int, and b is a reference to const int. While a is not const, the language permit the reference to const to be bound on a non const object. So it's a reference to const object that is bound to a mutable object. The type system won't allow you to modify the mutable object through the reference, because it may have been bound to a const object. In our case it isn't, but the tribe don't change. However, even declaration of a reference to const won't change the original declaration. The int a is still a mutable object. a may still change value:
a = 7;
This is valid, whatever references or other kind of variables have been declared. A variable declared as int (no const) can change, and nothing can prevent it from changing. Heck, even another program like cheat engine can change the value of a mutable variable. Even if you had rules in the language to guarantee that it won't be modified, there is nothing they will prevent the mutable variable from changing values. In any language. In machine language, a mutable value is permitted to change. However, maybe some API of the operating system can help you change the mutability of memory regions.
What can you do to solve this problem now?
If you want to be 100% sure an object won't be modified, you must have immutable data. You usually declare immutable objects with the const keyword :
const int a = 8;
int const& b = a;
// a cannot change, and b is guaranteed to be equal to 8 at this point.
If you don't want a to be immutable and still guarantee b to not change, use values instead of references :
int a = 8;
const int b = a;
a = 9;
// The value of b is still 8, and is guaranteed to not change.
Here, value sematic can help you have what you want.
Then const reference are there for what? There are there to express what you are going to do with the reference, and help enforce what can change where.
As the question has been further clarified, no there is no way to determine if the reference has been bound to a mutable or immutable object in the first place. There is, however, some tricks you can have to differentiate the mutability.
You see, if you want more information about the mutability to be passed along with the instance, you can store that information in the type.
template<typename T, bool mut>
struct maybe_immutable : T {
using T::T;
static constexpr auto mutable = mut;
};
// v--- you must sync them --v
const maybe_immutable<int, false> obj;
This is the most simple way to implement it, but a naive one too. The contained data will be conditionally immutable, but it forces you to sync template parameter and constness. However, the solution allows you to do this :
template<typename T>
void do_something(const T& object) {
if(object.mutable) {
// initially mutable
} else {
// initially const
}
}
I hope I understand you question correct it is not as explicit as so to say "D language" but with const r-value references you can make immutable parameters.
What I understand from immutable is forexample
void foo ( const int&& immutableVar );
foo(4);-> is ok
int a = 5;
foo(a);->is not ok

Is there any real use case for function's reference qualifiers?

Recently I learned about function's reference qualifiers, e.g.
struct foo
{
void bar() {}
void bar1() & {}
void bar2() && {}
};
Where I might need this feature, is there any real use case for this language feature ?
Where I might need this feature, is there any real use case for this language feature ?
The example you show is pretty useless, it's more useful when you have an overloaded function, one version that operates on lvalues and one that operates on rvalues.
Consider a type a bit like std::stringstream that owns a string and returns it by value. If the object is an rvalue, it can move the string instead of copying it.
class StringBuilder
{
public:
std::string get() const& { return m_str; }
std::string get() && { return std::move(m_str); }
private:
std::string m_str;
};
This means when you return a StringBuilder from a function and want to get the string out of it, you don't need a copy:
std::string s = buildString().get();
More generally, given a function f(const X&) if it would be useful to overload it with f(X&&), then given a member function X::f() it might be useful to change it to X::f() const& and overload it with X::f()&&
There are basically two uses:
To provide an optimized overload, for example to move a member out of a temporary object instead of having to copy it.
Prevent misuse of an API. For example, no one would expect
int a = 1 += 2;
to work and this would also cause a compile error. However
string b = string("foo") += "bar";
is legal if operator += is declared as
string & operator += (string const & o);
as is usually the case. Also this has the nasty side-effect of providing an lvalue-reference to your rvalue. Bad idea. This can easily be prevented by declaring the operator as
string & operator += (string const & o) &;

Prevent use of a class outside of temporary scope?

Is there a way to tell if an instance has been constructed in temporary scope or not, or prevent it from being used outside of temporary scope? I'm guessing there's not, but then again, I'm always surprised by the ability of C++ to exceed its own design limitations.
It's kind of a weird question, I admit, and I don't know how to "justify" the desire short of just providing the backstory.
The question arises from a shuttle class we use to glue together a scary number of legacy systems, each with their own notion of how data is represented. For a familiar example, take strings. We could overload each method in our API with each "style" of string:
void some_method(const char* arg);
void some_method(const std::string& arg);
void some_method(const QString& arg);
void some_method(const XmlDocString& arg);
void some_method(const wire_string& arg);
Or we could do:
void some_method(const StringArg& arg);
Where that helper class is (let's ignore string encodings for now and just assume bad old C-style strings for the purposes of this question):
class StringArg {
public:
StringArg() : m_data(""), m_len(0) {}
template<size_t N>
StringArg(const char (&s)[N]) : m_data(s), m_len(N-1) {}
StringArg(const char* s) : m_data(s?s:"") { m_len = strlen(m_data); }
template<class T>
StringArg(const T& t) : m_data(data_from(t)), m_len(len_from(t)) {}
const char* data() const { return m_data; }
const char* size() const { return m_len; }
private:
const char* m_data;
size_t m_len;
};
const char* data_from(const std::string& s) { return s.c_str(); }
size_t len_from(const std::string& s) { return s.size(); }
template<class XmlType>
const char* data_from(const XmlString<XmlType>& s) { return &s.content()[0]; }
template<class XmlType>
size_t len_from(const XmlString<XmlType>& s) { return s.byte_length(); }
ADL chooses the various data_from()/len_from() to get us a buffer backed by something else and its size. In reality there's extra metadata to capture important information about the nature of the buffer and how to iterate it, but the important point for this discussion is that StringArg is used in temporary scope, is cheap to copy, provides fast access to some buffer backed by something else on the outside of the interface whose type we now don't actually need to care about, and that any conversion, argument checking, or length calculations are done once at the boundary.
So there we are, someone is free to call it with two wildly different string classes:
interface_method(header() + body.str() + tail(), document.read().toutf8());
We don't need to care about the lifetime or the type of whatever's going on here, and internally we can pass around pointers to those buffers like candy, slice them up, parse them, log them in triplicate, without accidental allocation or lengthy memory copies. As long as we never hang on to those buffers, internally, this is safe and fast and has been a joy to maintain.
But as this API becomes more widely used, StringArg is (perhaps unsurpisingly) being used in places other than temporary scope, as if it were Yet Another String Class, and the resulting fireworks are impressive. Consider:
std::string t("hi");
write(StringArg(t+t)); //Yes.
StringArg doa(t+t); //NO!
write(doa); //Kaboom?
t+t creates a temporary whose content StringArg will point into. In temporary scope this is routine, nothing interesting to see here. Outside of it, of course, it's insanely dangerous. Dangling pointers to random stack memory. Of course, the second call to write() actually will work just fine most of the time, even though it is most clearly wrong, which makes detecting these mistakes quite difficult.
And here we are. I want to allow:
void foo(const StringArg& a);
foo(not_string_arg());
foo(t+t);
I want to prevent or detect:
StringArg a(t+t); //No good
And I'd be fine if the following wasn't possible, too, even though it's fine:
foo(StringArg(t+t)); //Meh
If I could detect the scope this thing was being constructed in, I could actually go and arrange to copy the content into a stable buffer in the constructor, similar to std::string, or throw an exception at runtime, or even better, if I could prevent it at compile time that'd ensure it was only used as designed.
Really, though, I only want StringArg to ever be the type of a method argument. An end user will never have to type "StringArg" in order to use the API. Ever. You'd hope that'd be easy enough to document away, but once some code looks like it works, it multiplies, and multiplies...
I have tried making StringArg non-copyable but that doesn't help much. I have tried creating an additional shuttle class and a non-const reference to try and fake out the implicit conversions in such a way they go my way. The explicit keyword seems to make my problem worse, promoting the typing of "StringArg". I tried messing around with an additional struct with partial specialization which is the only thing that knows how to construct a StringArg, and hiding the constructors for StringArg... something like:
template<typename T> struct MakeStringArg {};
template<> struct MakeStringArg<std::string> {
MakeStringArg(const std::string& s);
operator StringArg() const;
}
So then the user has to wrap all arguments with MakeStringArg(t+t) and MakeFooArg(foo) and MakeBarArg(bar)... existing code doesn't compile and in any case it kind of kills joy of using the interface.
I'm not above macro hacks at this point. My bag of tricks is looking pretty empty about now. Anyone have any advice?
So Matt McNabb points out
std::string t("hi");
const StringArg& a = t + t;
This causes a temporary StringArg to live longer than the content it points to. What I actually need is a way to determine when the full expression in which StringArg was constructed has ended. And that's actually doable:
class StringArg {
public:
template<class T>
StringArg(const T& t, const Dummy& dummy = Dummy())
: m_t(content_from(t)), m_d(&dummy) {
m_d->attach(this);
}
~StringArg() { if (m_d) m_d->detach(); }
private:
void stale() {
m_t = ""; //Invalidate content
m_d = NULL; //Don't access dummy anymore
//Optionally assert here
}
class Dummy {
public:
Dummy() : inst(NULL) {}
~Dummy() { if (inst) inst->stale(); }
void attach(StringArg* p) { inst = p; }
void detach() { inst = NULL; }
StringArg* inst;
};
friend class Dummy;
private:
const char* m_t;
Dummy* m_d;
};
With this, Matt's example and all the others I was hoping to prevent are thwarted: when the full expression ends, no StringArg points to anything suspect any longer, so any StringArg "given a name" is guaranteed to be useless.
(In case it's not clear why this works, it's because a Dummy must have been constructed before a StringArg that uses it, and therefore StringArg is guaranteed to be destroyed before the Dummy unless its lifetime is greater than the full expression in which it was constructed.)
I admit I didn't read your entire post, but you seem to have conflicting requirements. On the one hand you state that you want to avoid dangling references, but then you write:
write(StringArg(t+t)); //Yes.
StringArg doa(t+t); //NO!
If your only concern is to avoid dangling references then change the "NO!" to a "Yes", and in both cases move out of the temporary into a local value. The constructor would be:
StringArg(std::string &&arg)
{
this->the_arg = std::move(arg);
}
where the_arg is a std::string.
You could have StringArg store the string when it was constructed from an rvalue, and hold a reference to a string if it was constructed from an lvalue.
If you want a class which methods could be used only by rvalue objects, you could use rvalue qualifier on methods in C++11:
class only_rvalue
{
public:
only_rvalue() = default;
only_rvalue( const only_rvalue& ) = delete;
only_rvalue( only_rvalue&& ) = default;
only_rvalue& operator=( const only_rvalue&& ) = delete;
only_rvalue& operator=( only_rvalue&& ) = default;
void foo() &&;
void bar() &&;
void quux() &&;
};
only_rvalue create();
int main()
{
only_rvalue{}.foo(); //ok
create().bar(); //ok
only_rvalue lvalue;
lvalue.foo(); //ERROR
}