假设我有一个跨平台Path
类,例如:
class Path {
public:
// ...
Path parent() const; // e.g., /foo/bar -> /foo
std::string const& as_utf8() const {
return path;
}
private:
std::string path;
};
成员函数返回 path的parent()
父路径this
,因此它(正确地)返回一个新构造Path
的表示它的对象。
as_utf8()
对于在操作系统级别将路径表示为 UTF-8 字符串的平台(例如,Unix),直接返回对内部表示的引用似乎是合理的,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()
来查看它是否返回 a似乎会给调用者带来过度的负担const&
:如果是,那么调用者必须使用一个对象而不是const&
; _ 如果它返回一个对象,那么调用者可以使用const&
.
那么有没有什么办法可以解决这个问题,让 API 在大多数情况下既高效又能防止用户从看似无害的代码中获取悬空引用?
顺便说一句,这是使用 g++ 5.3 编译的。可能应该延长临时的生命周期,但是编译器有一个错误。