Date: Fri, 13 Nov 2020 11:20:42 +0100
On 13/11/2020 10:04, Amir Kirsh via SG20 wrote:
>
> Taking this approach in users' code is possible, though a bit cumbersome
> today:
>
> class Person {
> std::string name;
> public:
> Person(std::string name): name(std::move(name)) {}
> const std::string& getName() const & { return name; }
> const std::string& getName() const && = delete;
This makes legitimate code not work:
std::string name = // not a reference
getPerson().getName();
> // or:
> // std::string getName() const && { return name; }
This works but makes a copy instead of moving the data member into the
return object. You'd also need something like:
std::string getName() && { return std::move(name); }
Usual disclaimer: you justify this because you know that std::string is
reasonably cheap to move, so you can afford the cost of return by value
in these circumstances. If you were to return something not necessarily
cheap to move, then justifying the return by value -- even from rvalue
overload -- is not so easy. So you'd return by rvalue reference
(otherwise, a chain like getArrayOfPersons().getFirst().getName()
creates N possibly expensive temporaries). And we're back to square one
for the general case.
Other usual disclaimer, this assumes that "moved from" means "partially
formed", not "valid but unspecified" like the stdlib does (you've likely
just broken class invariants).
Moreover: going this route for any "getter" makes the implementation
alone, today, terribly cumbersome (this is probably where "deducing
this" could help). I still find that the teachability of all of this is
nothing but dreadful.
My 2 c,
>
> Taking this approach in users' code is possible, though a bit cumbersome
> today:
>
> class Person {
> std::string name;
> public:
> Person(std::string name): name(std::move(name)) {}
> const std::string& getName() const & { return name; }
> const std::string& getName() const && = delete;
This makes legitimate code not work:
std::string name = // not a reference
getPerson().getName();
> // or:
> // std::string getName() const && { return name; }
This works but makes a copy instead of moving the data member into the
return object. You'd also need something like:
std::string getName() && { return std::move(name); }
Usual disclaimer: you justify this because you know that std::string is
reasonably cheap to move, so you can afford the cost of return by value
in these circumstances. If you were to return something not necessarily
cheap to move, then justifying the return by value -- even from rvalue
overload -- is not so easy. So you'd return by rvalue reference
(otherwise, a chain like getArrayOfPersons().getFirst().getName()
creates N possibly expensive temporaries). And we're back to square one
for the general case.
Other usual disclaimer, this assumes that "moved from" means "partially
formed", not "valid but unspecified" like the stdlib does (you've likely
just broken class invariants).
Moreover: going this route for any "getter" makes the implementation
alone, today, terribly cumbersome (this is probably where "deducing
this" could help). I still find that the teachability of all of this is
nothing but dreadful.
My 2 c,
-- Giuseppe D'Angelo | giuseppe.dangelo_at_[hidden] | Senior Software Engineer KDAB (France) S.A.S., a KDAB Group company Tel. France +33 (0)4 90 84 08 53, http://www.kdab.com KDAB - The Qt, C++ and OpenGL Experts
Received on 2020-11-13 04:20:49