Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disable writes on temporary returned by getter?

Tags:

c++

I have a getter which returns a temporary object, copy of the internal object.

Something like the following:

class Foo
{
public:
    QString name() {return m_name;}
    void setName(const QString &name);
private:
    QString m_name;
}

The intended usage of the setter/getter is to get the data through name() and set the data through setName().

But sometimes, incorrectly, I tend to do the following:

name().clear();

Or some other modification directly to the getter's return.

NOTE that the intention with the above line (and with similar modifications) is to clear the name in Foo, not the temporary variable, so the line above compiles correctly, but behaves incorrectly, since it will clear the temporary, not Foo's member.

How can I disable such an incorrect usage, and get an error at compile time?

Note that I may have both, third-party types (which I cannot modify, like std::string, or the QString above) and custom types (which I can modify for this).

Edit:

Note that overloading with const, &, && or similar are not useful, since I may have something like:

Foo foo;
foo.name().clear();

Which no matter what overload you choose, it will always compile fine.

Also, all the modifications to the internal member must go through setName(), since it will apply some logic and notify some other objects, so any modification not made through the interface must be avoided. This prevents the getter returning by non-const reference to allow the above usage or make the private member as public.

like image 558
LoPiTaL Avatar asked Jun 08 '21 08:06

LoPiTaL


1 Answers

Maybe try

const QString name() const {return m_name;}

This will prevent direct use of:

foo.name().clear();

Please also note, as underlined in the comments, that as the returned QString is a copy, foo.name().clear(); won't modify foo.m_name. But yes, a quick read of the code can be confusing.


EDIT extra reads: when-use-const-3-return-types


A more involved solution, inspired by thoughts-about-getters-and-setters, would be

class Foo {
   
  public:
    ... 

    const QString& name() const & {return m_name;}   
    QString name() && {return std::move(m_name);}

  private:
    QString m_name;         
};

Please also note that the blog post encourages a simple solution like this one:

class Foo {
  ... 
  public
    QString name;         
};

This is an economical and viable solution when you do not have to enforce some invariant or do some other actions in the 'setter' method.

like image 94
Picaud Vincent Avatar answered Oct 17 '22 15:10

Picaud Vincent