Что я должен реализовать, SetMember (постоянный член &), SetMember (член) или SetMember (член &&)? - PullRequest
0 голосов
/ 02 июля 2018

Позвольте Memeber быть классом, и давайте предположим, что я понятия не имею, поддерживает ли он или нуждается в семантике перемещения. Скажем, для всех намерений и целей это еще даже не указано / написано. Какой случай функций SetMember следует реализовать в классе Outer, в котором Member является членом?

Если бы Member не поддерживал ход, я бы сделал это:

class Member {
public:
    Member(Member&&) = delete;
    Member& operator=(Member&&) = delete;
};

class Outer {
    Member m_member;
public:
    void SetMember(const Member& o) { m_member = o.m_member; } // makes a copy
};

И если Member поддержит движение, я сделаю это:

class Member {
public:
    Member(Member&&);
    Member& operator=(Member&&);
};

class Outer {
    Member m_member;
public:
    void SetMember(Member o) { m_member = std::move(o.m_member); } // makes a copy if needed
};

Но так как я не знаю, есть ли у него движение или нет, мне нужно реализовать оба? Как это:

class Outer {
    Member m_member;
public:
    void SetMember(const Member& o) { m_member = o.m_member; } // makes a copy
    void SetMember(Member&& o) { m_member = std::move(o.m_member); } // makes no copy
};

Или я должен это сделать?

class Outer {
    Member m_member;
public:
    template <class T>
    void SetMember(T&& o) { m_member = std::forward<T>(o.m_member); }
};

Почему я не доволен этими двумя решениями:

  • В первом решении я вижу дублирование кода, которое необходимо только потому, что я не знаю некоторых деталей реализации Member, а именно, поддерживает ли он перемещение или нет.
  • Второе решение оставляет меня с ошибками компиляции вместо ошибок intelli-смысла всякий раз, когда я пытаюсь использовать SetMember для неправильного типа. Также мне нужен шаблон только потому, что некоторые детали реализации Member.

Как правильно справиться с этой ситуацией?

1 Ответ

0 голосов
/ 02 июля 2018

Насколько я знаю, переход по значению в установщиках больше не рекомендуется. По крайней мере, в случае std::strings, когда setter вызывается несколько раз, весьма вероятно, что у переменной назначения достаточно памяти, зарезервированной для нового значения, и дешевле просто скопировать содержимое в уже выделенную строку, затем создать временную строку и переместить это.
Поэтому независимо от того, является ли тип перемещаемым или нет, рекомендуется передавать по константной ссылке и делать копию внутри установщика. Если последующее профилирование показывает, что временное значение часто используется в качестве аргумента, а стоимость копирования делает его целесообразным для оптимизации, может быть добавлена ​​перегрузка для ссылки на rvalue.
Смотри также https://stackoverflow.com/a/26286741/113662

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...