临时数据成员和API设计的终身扩展

Pau*_*cas 8 c++ api-design temporary data-members

假设我有一个跨平台Path类,如:

class Path {
public:
    // ...
    Path parent() const;                // e.g., /foo/bar -> /foo

    std::string const& as_utf8() const {
        return path;
    }
private:
    std::string path;
};
Run Code Online (Sandbox Code Playgroud)

所述parent()成员函数返回的父路径this的路径,所以它(正确)返回一个新构造的Path对象,它表示它.

对于将OS级别的路径表示为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)
Run Code Online (Sandbox Code Playgroud)

这两行都很好,因为:

  • 假设my_path持续存在,那么s仍然有效.
  • 返回的临时对象的生命周期parent()const&.

到现在为止还挺好.但是,如果我有以下代码:

std::string const &s = my_path.parent().as_utf8(); // WRONG
Run Code Online (Sandbox Code Playgroud)

那么这是错误的,因为返回的临时对象parent()没有有它的寿命延长,因为const&不是指的是暂时的,而到它的数据成员.此时,如果您尝试使用s,您将获得垃圾或核心转储.如果代码是:

    std::string as_utf8() const {                 // Note: object and NOT const&
        return path;
    }
Run Code Online (Sandbox Code Playgroud)

然后代码是正确的.但是,每次调用此成员函数时创建临时文件都是低效的.言下之意也是没有 "消气"成员函数应不断回到自己的数据成员的引用.

如果API保持原样,那么它似乎会给调用者带来不必要的负担,必须查看返回类型as_utf8()以查看它是否返回const&:如果是,则调用者必须使用对象而不是一个const&; 如果它返回一个对象,那么调用者可以使用a const&.

那么有什么方法可以解决这个问题,这样API在大多数情况下都是高效的,但却阻止用户从看似无害的代码中获取悬空引用?


顺便说一句,这是使用g ++ 5.3编译的.这有可能是暂时的寿命应该延长,但是编译器有一个错误.

Rak*_*111 7

你可以做的是创建2个不同的版本as_utf8(),一个用于左值,一个用于右值.但是你需要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
}
Run Code Online (Sandbox Code Playgroud)