У меня есть геттер, который возвращает временный объект, копию внутреннего объекта.

Что-то вроде следующее:

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

Предполагаемое использование установщика / получателя - получить данные через name() и установить данные через setName().

Но иногда я делаю неправильно:

name().clear();

Или какая-то другая модификация непосредственно для возврата геттера.

ОБРАТИТЕ ВНИМАНИЕ, что цель вышеупомянутой строки (и с аналогичными изменениями) состоит в том, чтобы очистить имя в Foo, а не временную переменную, поэтому строка выше компилируется правильно, но ведет себя некорректно, поскольку она очищает временную, а не временную переменную. Член Фу.

Как я могу отключить такое неправильное использование и получить ошибку во время компиляции?

Обратите внимание, что у меня могут быть как сторонние типы (которые я не могу изменить, например std :: string или QString выше), так и пользовательские типы (которые я могу изменить для этого).

Редактировать:

Обратите внимание, что перегрузка с помощью const, &, && или аналогичных бесполезна, так как у меня может быть что-то вроде:

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

Независимо от того, какую перегрузку вы выберете, она всегда будет компилироваться нормально.

Кроме того, все изменения внутреннего члена должны проходить через setName(), поскольку он будет применять некоторую логику и уведомлять некоторые другие объекты, поэтому следует избегать любых изменений, внесенных не через интерфейс. Это предотвращает возврат получателя по неконстантной ссылке, чтобы разрешить указанное выше использование или сделать закрытый член общедоступным.

c++
5
LoPiTaL 8 Июн 2021 в 11:34

2 ответа

Лучший ответ

Может попробовать

const QString name() const {return m_name;}

Это предотвратит прямое использование:

foo.name().clear();

Также обратите внимание, как подчеркнуто в комментариях, поскольку возвращенная QString является копией , foo.name().clear(); не будет изменять foo.m_name. Но да, быстрое чтение кода может сбить с толку.


ИЗМЕНИТЬ дополнительные чтения: when-use- const-3-return-types


Более сложное решение, основанное на think-about-getters- и установщики, будут

class Foo {
   
  public:
    ... 

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

  private:
    QString m_name;         
};

Также обратите внимание, что сообщение в блоге предлагает простое решение, подобное этому:

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

Это экономичное и жизнеспособное решение, когда вам не нужно принудительно применять какой-либо инвариант или выполнять какие-либо другие действия в методе установки.

5
Picaud Vincent 8 Июн 2021 в 17:21

Если бы у вас вместо этого было

class Foo
{
public:
    QString & name() {return m_name;}
    const QString & name() const {return m_name;}
    /* optionally also */
    void setName(const QString & name) { m_name = name; }
private:
    QString m_name;
}

Тогда у вас не возникнет проблем с изменением значений prvalues

0
Caleth 8 Июн 2021 в 08:50