Ref-квалифицированные разбиения функций-членов на константные значения

У меня есть Maybe класс, основанный на стеке, который может содержать данный тип. У нас есть определенные функции, которые возвращают Maybe содержащий изменчивую или постоянную ссылку. Это в основном для сокращения шаблонов, поиска и ненужных копий.

Map<String, Foo> map;

// Normal C++
auto it = map.find("foo");
if (it != map.end())
  doStuff(*it);

// Has an extra lookup, bad
if (map.contains("foo"))
  doStuff(map.get("foo"));

// Uses Maybe
if (auto val = map.maybe("foo"))
  doStuff(*val);

// Also possible:
// apply calls the function with *this as argument if this is valid
map.maybe("foo").apply(&doStuff);

Тем не менее, это проблематично, когда map является временным:

Map<String, Foo> map;
Map<String, Foo> getMap() { return map; } // Returns a copy of map

if (auto val = getMap().maybe("foo")) // Returns Maybe<Foo&> to temporary
  doStuff(*val); // Very bad, *val has already been deleted

С другой стороны, потому что Maybe<Foo> конструктивно из Maybe<Foo&> (в общем, Maybe<T2> конструктивно из Maybe<T> если T2 конструктивно из T) тогда если я напишу это, это не проблема.

if (Maybe<Foo> val = getMap().maybe("foo"))
  doStuff(*val); // OK, val contains a copy

После того, как коллега наткнулся на эту проблему, у меня возникла блестящая идея использовать функции-члены с повторными квалификациями в местах, которые могут вернуть Maybe<T&> вернуть Maybe<T> вместо этого, если это значение.

Maybe<Val> Map<Key, Val>::maybe(Key const& key) &&;
Maybe<Val const&> Map<Key, Val>::maybe(Key const& key) const&;
Maybe<Val &> Map<Key, Val>::maybe(Key const& key) &;

Но у меня возникли проблемы с выяснением того, что делать в случае const&&;

Если оставить без, это вызвало бы const& версия, которая плоха, потому что это вернет ссылку.

Я думал сделать && версия а const&& версия, чтобы избежать повторения; однако тогда мне нужно будет скопировать, вместо того, чтобы перемещать внутреннее значение. И я недостаточно понимаю семантику const&& знать, будет ли это приемлемо для const_cast внутренне, или если это вызовет безумие и истерию, пока я мутирую const&&, Я бы предпочел не писать две копии этой функции, если мне не нужно.

Какова нормальная лучшая практика в этой ситуации? Нужно ли мне писать все 4 функции? Или я могу сойти с ума с 3?

Есть ли лучший способ избежать этой проблемы с ссылками? Это только проблема, потому что auto обычно удаляет ссылки, поэтому вы не можете случайно взять ссылку на временную ссылку, но потому что тип Maybe это уже обычное значение, это просто обёртка ссылочного типа, становится возможным выстрелить себе в ногу. Просто говорю "ну не используй auto в таком случае "очень заманчиво, но все-таки очень легко случайно запутаться, и я бы предпочел, чтобы было трудно сделать неправильную вещь".

2 ответа

Решение

Там нет, как вы могли бы получить const&& в любом случае в хорошем коде.

Единственные способы

  1. Вызов функции, возвращающей const T, (И в любом случае наличие такого типа возврата - плохая идея.)
  2. Вызов функции, возвращающей const T&&, (Дито.)
  3. Умышленное приведение к const&&, (Что вы не будете делать в любом случае.)
  4. Неявное преобразование из &&, (Этого не произойдет, потому что у вас есть перегрузка, принимающая по r-значению.)

Таким образом, правильный способ, если вы хотите пуленепробиваемый ваш API, это просто deleteс перегрузкой:

Maybe<Val &> maybe(Key const& key) const&& = delete;

Я бы сказал, что это не проблема. Рассмотрим программу

#include <map>
#include <cstdio>
int main() {
  int& x = std::map<int, int>{{3, 4}}[3];
  printf("%d\n", x);
}

Ссылка x будет болтаться после уничтожения карты (делая поведение последней строки неопределенным). Стандартная библиотека не делает ничего, чтобы предотвратить такую ​​ситуацию.

Я также никогда не слышал, чтобы кто-то случайно совершил такую ​​ошибку.

С вашей картой такая же ситуация.

ИМО, возвращаясь либо Maybe<Val> или же Maybe<Val&> В зависимости от категории значения карты это слишком запутанно. Просто думай дважды каждый раз, когда звонишь .maybe на временном объекте.

Другие вопросы по тегам