Продление срока службы временных данных членов и дизайн API

Предположим, у меня есть кроссплатформенный 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;
}

тогда код будет правильным. Однако было бы неэффективно создавать временные при каждом вызове этой функции-члена. Подразумевается также, что нет функции-члены «getter» должны Когда-либо вернуть ссылки на свои данные членов.

Если API оставить как есть, то кажется, что вызывающая сторона будет неоправданно обременена поиском возвращаемого типа as_utf8() чтобы увидеть, возвращает ли он const& или нет: если это так, то вызывающая сторона должен использовать объект и не const&; если он возвращает объект, то вызывающая сторона может использовать const&,

Так есть ли способ решить эту проблему, так что API в большинстве случаев эффективен, но при этом не позволяет пользователю получать свисающие ссылки из, казалось бы, безобидного кода?


Кстати, это было скомпилировано с использованием g ++ 5.3. Возможно, что время жизни временного должен быть расширенным, но в компиляторе есть ошибка.

8

Решение

Что вы можете сделать, это создать 2 разные версии as_utf8()один для lvalues ​​и один для rvalues. Вам понадобится C ++ 11, хотя.

Таким образом, вы получаете лучшее из обоих миров: const& когда объект не временный, а эффективный ход, когда это не так:

std::string const& as_utf8() const & {
// ^^^ Called from lvalues only
return path;
}

std::string as_utf8() const && {
// ^^^^ Called from rvalues only
return std::move(path); //We don't need path any more
}
7

Другие решения

На мой взгляд, руководящим принципом относительно того, возвращать ли ссылку или объект, является изучение определенной роли исходного класса.

то есть метод, представляющий простое свойство (аргументирует для ссылки, особенно если он неизменный), или это порождающий что-то?

Если он генерирует новый объект или представление, мы можем разумно ожидать, что он возвратит отдельный объект.

Пользователи API, как правило, привыкли понимать, что свойства не переживают свои хост-объекты. Это, конечно, может быть ясно указано в документации.

например

struct path
{
/// a property
/// @note lifetime is no longer than the lifetime of this object
std::string const& native() const;

/// generate a new string representation in a different format
std::string to_url() const;

};

Я лично избегал бы префикса as_ в этом случае, так как для меня это предполагает, что мы возвращаем новое представление того же объекта, например:

struct world
: std::enable_shared_from_this<world>
{
struct sky {} my_sky_;

/// returns a shared_ptr to my sky object, which shares its lifetime
/// with this world.
std::shared_ptr<sky> as_sky()
{
return std::shared_ptr<sky>(shared_from_this(), std::addressof(my_sky_));
}
};
1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector