Предположим, у меня есть кросс-платформенный класс Path
, например:
class Path {
public:
// ...
Path parent() const; // e.g., /foo/bar -> /foo
std::string const& as_utf8() const {
return path;
}
private:
std::string path;
};
Функция-член parent()
возвращает родительский путь пути this
, поэтому она (правильно) возвращает вновь созданный объект Path
, который его представляет.
Для платформы, которая представляет пути на уровне ОС в виде строк UTF-8 (например, Unix), кажется разумным, чтобы as_utf8()
возвращала ссылку непосредственно на внутреннее представление path
, поскольку оно уже в кодировке UTF-8. .
Если у меня есть код вроде:
std::string const &s = my_path.as_utf8(); // OK (as long as my_path exists)
// ...
Path const &parent = my_path.parent(); // OK (temporary lifetime extended)
Обе эти строки хороши, потому что:
- Если предположить, что
my_path
сохраняется, тоs
остается действительным. - Время жизни временного объекта, возвращаемого
parent()
, продлевается наconst&
.
Все идет нормально. Однако, если у меня есть код вроде:
std::string const &s = my_path.parent().as_utf8(); // WRONG
тогда это неправильно, потому что временный объект, возвращаемый parent()
, не имеет продленное время жизни, потому что const&
не ссылается на временный объект, а на член данных этого. На этом этапе, если вы попытаетесь использовать s
, вы получите либо мусор, либо дамп ядра. Если бы вместо этого был код:
std::string as_utf8() const { // Note: object and NOT const&
return path;
}
тогда код будет правильным. Однако было бы неэффективно создавать временный объект при каждом вызове этой функции-члена. Подразумевается также, что никакие "геттерные" функции-члены не должны никогда возвращать ссылки на свои данные-члены.
Если API оставить как есть, то на вызывающую сторону будет возлагаться чрезмерное бремя необходимости смотреть на тип возвращаемого значения as_utf8()
, чтобы увидеть, возвращает ли она const&
или нет: если это так, то вызывающая сторона должен использовать объект, а не const&
; если он возвращает объект, то вызывающая сторона может использовать const&
.
Итак, есть ли способ решить эту проблему, чтобы API был эффективным в большинстве случаев, но не позволял пользователю получать оборванные ссылки из, казалось бы, безобидного кода?
Кстати, это было скомпилировано с использованием g++ 5.3. Возможно, время жизни временного должно быть увеличено, но в компиляторе есть ошибка.
temp().member
иtemp().get()
, гдеget()
возвращаетmember
. - person aschepler   schedule 24.08.2016get
возвращает ссылку на член, у вас есть член, поскольку ссылка является просто псевдонимом. - person NathanOliver   schedule 24.08.2016get
возвращает ссылку на член? Компилятор может видеть только то, чтоget
возвращает ссылку. Нет, временное продление срока службы происходит только тогда, когда вы получаете NSDM, а не вызываете функцию-член. - person Nicol Bolas   schedule 24.08.2016get
не является встроенным? - person aschepler   schedule 24.08.2016