• 可以std::unique_ptr只管理指针,还是也可以管理花式指针(类似指针的类型)?

我假设“花哨指针也是如此”,因为对于文件/套接字等资源,花哨指针可能是一个很好的工具。而且似乎没有理由std::unique_ptr不支持它们。

  • 为什么测试托管指针是否为空的方法不一致?

std::unique_ptr在(GCC)中,有不同的方法来测试托管指针是否为空:

  • ~unique_ptr():(if (__ptr != nullptr)代码
  • reset():(if (__old_p)代码
  • operator bool():(return get() == pointer() ? false : true;代码

问题是它们对指针类型有不同的要求:

  • bool operator ==(pointer, nullptr_t)
  • operator bool()
  • bool operator ==(pointer, pointer)

不一致的用法意味着所有这些都是需要的,但其中一个在语义上就足够了。

#include <memory>

using namespace std;

class File {
    FILE * pf_ = nullptr;
public:
    File() = default;
    File(const char * pathname) { /*...*/ };
    void Close() { /*...*/ };

    // All are needed to make std::unique_ptr work
    explicit operator bool() const { return pf_ == nullptr; }
    bool operator ==(nullptr_t) const { return pf_ == nullptr; }
    bool operator ==(File) const { /*...*/ return true; };
};

struct FileCloser {
    using pointer = File;
    void operator ()(File p) const { p.Close(); }
};

int main() {
    using FilePtr = unique_ptr<File, FileCloser>;
    FilePtr p(File("./abc"));
    if(p)
        p.reset();
}

恕我直言,std::unique_ptr应该对指针类型要求最低。一种解决方案是添加静态成员,例如__test_p,并使用它来一致地测试空性:

template<typename T, typename D = std::default_delete<T>>
class unique_ptr
{
// ...
private:
    static constexpr bool __test_p(pointer p) noexcept {
        if constexpr (is_convertible_v<pointer, bool>)
            return bool(p);
        else if constexpr (requires {{ p != nullptr} -> convertible_to<bool>; })
            return p != nullptr;
        else
            return p != pointer();
    }
// ...
};

10

  • 6
    你把事情搞得太复杂了。你有File一个包装FILE *类型的类。所以只需使用类的析构File函数即可关闭文件。


    – 


  • 1
    它支持实现的类指针类型。指针类型通过删除器的成员指定pointer


    – 

  • 1
    “恕我直言,std::unique_ptr应该对指针类型有最低要求” – 是的,嗯,你知道,这只是你的看法,伙计。不幸的是,pointer成员类型必须满足 NullablePointer


    – 

  • 1
    说实话,我不知道“花哨的指针”是什么,它们在 C++ 标准中没有任何地方描述。而且 std::unique_ptr 可以隐式转换为 bool(以检查是否为空),所以总的来说你的观点是什么?如果你想要更多行为,请编写一个自定义包装器来包装 FILE(或者只使用 std::iostream 并获得所有 C++ 好处)


    – 


  • 2
    @MarekR 如果您这样做了,那么它就File服务于 2 个主人;首先,它是 的 API 包装器FILE*并且它是一个 RAII 管理器。有时您正在使用提供FILE*您不拥有的 的 C 代码,或者您需要向FILE*可能拥有所有权的 C 代码提供 ;File编写的类使这两个操作都更容易。(即,您可以安全地执行File(SOME_FILE_POINTER).Operation()而无需关闭文件)。然后,唯一的指针File添加了 RAII 功能。


    – 


最佳答案
1

std::unique_ptr 只能管理指针,还是也可以管理花式指针(类似指针的类型)?

是的

要求std::unique_ptr<T, Deleter>如下:

  • Deleter必须是FunctionObject或对FunctionObject 的左值引用或对函数的左值引用,可使用类型参数进行调用unique_ptr<T, Deleter>::pointer

  • std::remove_reference_t<Deleter>::pointer如果存在,则必须满足

除其他事项外,NullablePointer必须满足您声称不一致的所有三个要求,并且它们必须彼此一致。

为什么测试托管指针是否为空的方法不一致?

拥有“冗余”操作是对约束的用户与约束的实施者的一种权衡,这并不是“错误的”。

虽然确实operator bool必须等于ptr != nullptr,并且ptr == nullptr必须等于,但所有比较都ptr == pointer(nullptr)采用 和 更符合人体工程学。通过确保每个NullablePointer都可以执行原始指针可以执行的所有操作,可以编写期望原始指针的代码,并且“适用于”花哨的指针。operator bool

恕我直言,std::unique_ptr 应该对指针类型有最低要求。

这是你的意见。委员会另有选择。

1

  • 谢谢你的解释!我想如果它是通过concept实现的,那就没那么令人困惑了,尽管我知道它是在conceptunique_ptr之前引入的


    –