【发布时间】:2016-12-31 21:03:12
【问题描述】:
假设我有一个跨平台的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 编译的。临时应该的生命周期可能会延长,但是编译器有错误。
【问题讨论】:
-
那么这是错误的,因为 parent() 返回的临时对象没有延长其生命周期,因为 const& 不是指临时对象,而是它的数据成员这是错误的。我正在寻找显示寿命延长的问题
-
@NathanOliver 但是
temp().member和temp().get()之间存在区别,get()恰好返回member。 -
@NathanOliver:编译器怎么可能知道
get返回一个成员的引用?编译器只能看到get返回一个reference。不,临时生命周期延长仅在您获得 NSDM 时发生,而不是调用成员函数。 -
@NathanOliver 如果
get不是内联的,编译器如何知道延长临时的生命周期? -
好的,只有当你直接引用成员时,编译器才被允许延长生命周期。谢谢。
标签: c++ api-design temporary data-members