返回对std :: unique_ptr的引用的原因

Gre*_*Cat 6 c++ shared-ptr unique-ptr

我想知道是否有任何合理的理由在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
Run Code Online (Sandbox Code Playgroud)

请注意,如果我们只返回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); }
Run Code Online (Sandbox Code Playgroud)

我怀疑一般的经验法则是所有这些案件都值得使用std::shared_ptr.我对吗?

pat*_*gan 5

这有两个用例,在我看来,这表明设计不佳。拥有非常量引用意味着您可以窃取或替换资源,而无需提供单独的方法。

// 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>;
Run Code Online (Sandbox Code Playgroud)

我强烈反对这些做法,因为它们容易出错且可读性较差。最好提供如下所示的界面,前提是您确实需要此功能。

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); }
Run Code Online (Sandbox Code Playgroud)