我想知道是否有合理的理由在C ++中通过引用返回唯一指针,即std::unique_ptr<T>&
?
我之前从未见过这个技巧,但是我得到的新项目似乎使用了这个模式很多。从第一眼看,它只是有效地打破/规避了“独特的所有权”合同,使得无法在编译时捕获错误。请考虑以下示例:
class TmContainer {
public:
TmContainer() {
// Create some sort of complex object on heap and store unique pointer to it
m_time = std::unique_ptr<tm>(new tm());
// Store something meaningful in its fields
m_time->tm_year = 42;
}
std::unique_ptr<tm>& time() { return m_time; }
private:
std::unique_ptr<tm> m_time;
};
auto one = new TmContainer();
auto& myTime = one->time();
std::cout << myTime->tm_year; // works, outputs 42
delete one;
std::cout << myTime->tm_year; // obviously fails in the runtime, as `one` is deleted
请注意,如果我们只返回std::unique_ptr<tm>
(不是引用),则会引发明确的编译时错误,或强制使用移动语义:
// Compile-time error
std::unique_ptr<tm> time() { return m_time; }
// Works as expected, but m_time is no longer owned by the container
std::unique_ptr<tm> time() { return std::move(m_time); }
我怀疑一般的经验法则是所有这些情况都需要使用std::shared_ptr
。我是对的吗?
答案 0 :(得分:3)
这有两个用例,在我看来,这表明设计不好。拥有非const引用意味着您可以窃取资源或替换它而无需提供单独的方法。
// Just create a handle to the managed object
auto& tm_ptr = tm_container.time();
do_something_to_tm(*tm_ptr);
// Steal the resource
std::unique_ptr<TmContainer> other_tm_ptr = std::move(tm_ptr);
// Replace the managed object with another one
tm_ptr = std::make_unique<TmContainer>;
我强烈主张反对这些做法,因为它们容易出错并且可读性较差。如果您确实需要此功能,最好提供如下界面。
tm& time() { return *m_time; }
std::unique_ptr<tm> release_time() { return {std::move(m_time)}; }
// If tm is cheap to move
void set_time(tm t) { m_time = make_unique<tm>(std::move(t)); }
// If tm is not cheap to move or not moveable at all
void set_time(std::unique_ptr t_ptr) { m_time = std::move(t_ptr); }
答案 1 :(得分:1)
这是一个评论太久了。我对请求的用例没有好主意。我想象的唯一的东西是实用程序库的一些中间件。
问题是你想要什么,需要建模。什么是语义。返回参考没有任何有用的知识。
您的示例中唯一的优点是没有显式的析构函数。如果你想制作这段代码的精确镜像,它就是一个原始指针恕我直言。应该使用的确切类型取决于他们想要建模的确切语义。
也许您展示的代码背后的意图是返回一个非拥有指针,该指针通过原始指针建模(正如我所知)。如果你需要保证对象是活着的,那么你应该使用shared_ptr
但请注意,这意味着共享所有权 - 即将其从TmContianer
中分离出来。
使用原始指针会使你的代码失败,但有人可能会说,没有理由明确delete
,并且可以通过范围正确管理对象的生命周期。
这当然是值得商榷的,因为语言和单词和短语的含义是,但我的经验说,c++
人们如何写,说和理解指针。
答案 2 :(得分:0)
std::unique_ptr
无法满足 CopyConstructible 或 CopyAssignable 的要求。
因此,如果需要,必须将对象作为参考返回。