【问题标题】:Smart Pointer advanced implementation [help, advice, feedback]智能指针高级实现[帮助、建议、反馈]
【发布时间】:2021-05-06 15:22:09
【问题描述】:

我想更深入地了解 C++。在 STL 中做出的决定是我想理解的,而且仅从代码中很难理解。

我的想法是自己实现一些 STL 以了解其中的缺陷,从而提高我对 C++ 的理解并改进我的代码。而且我想在 STL 容器中有一些特性,STD 没有资源处理类的销毁通知。我创建了我的 SharedPointer 的扩展版本,以包含一个 std::function 作为删除通知器。

我发现了一些麻烦。

以这段代码为例:SmartPointer.hpp

这是我想出的一些代码,有一些问题。

短:

  1. 已知问题
    1. 派生类不起作用
    2. 抱怨类型不完整
  2. 未知问题

长:

1.1。派生类不起作用

类型转换后,仅将 T 作为类型将不起作用。这个想法是将 OrigT 作为第二个参数传递,所以我总是知道 ptr 指向什么类型。我可以将其转换回去并调用正确的析构函数。

考虑

SharedPointer<Derived> member = base.Cast<Derived>();

将创建 T = OrigT 并且类型在我假设的断言强制转换后将不匹配。我无法想象如何解决这个问题。

if (!shared->HasReferences())
{
    delete shared;
    
    OriginalValuePointer origPtr = dynamic_cast<OriginalValuePointer>(ptr);
    delete origPtr;
}

1.2。抱怨类型不完整

在我的示例中,我收到了有关不完整类型的投诉。但我不知道为什么。目前我正在考虑制作 operator* 和 operator-> 模板,这也将是在黑暗中拍摄。我不知道它为什么会抱怨,我想问你是否可以在这里指出问题。

Same code as above in compiler complaint

2.2。我认为 stackoverflow 不是寻求反馈的理想场所,但考虑到我的两个问题,我还是想问一下。

  • 有没有人有任何可读和理想解释的智能指针的来源?我发现的那些与我的期望不太相符。它们要么过于简单,要么在关键点没有包含解释。

  • 我希望能对代码提供一些直接反馈。当然远离编码风格;-)。你有什么直接看到我犯了我会后悔的错误吗?有什么可以做得更好的吗? (例如, .Cast as member 恕我直言,这是一个糟糕的选择。一旦它不是指针的直接属性,我认为它可能会导致我还不知道的缺陷。)

非常感谢您的帮助和意见。

保持健康。

【问题讨论】:

  • 有关智能指针设计空间的详细讨论,您可以查看 Alexandrescu 的 Modern C++ Design。它早于 C++11,但绝对值得一读
  • ShadedDataPointer 可能是错字
  • 有点吹毛求疵,但 STL 是 the Standard Template Library 的缩写,它是 the C++ standard library 的前身(但不同于)。
  • 有关现有代码的反馈,请考虑在codereview.stackexchange.com 发帖。
  • I'd appreciate some direct feedback on the code. 如果你想对代码有反馈,你必须在你的问题中包含它。指向外部网站的链接随时可能失效,这可能会使问题和答案变得无用。除此之外,codereview.stackexchange.com 可能是一个更好的地方,或者可能专注于问题的一部分,比如你如何允许强制转换,减少部分代码。

标签: c++ stl shared-ptr smart-pointers


【解决方案1】:
  • 普通 C++ 类使用snake_case,而不是CamelCase。
  • 这个类不是线程安全的(你可能知道,但值得一提)
  • NumReferences 通过引用返回计数,这没有用,并且比通过 int 返回稍慢。
  • 类中定义的所有方法都自动为inline,因此您在任何地方都不需要。
  • operator ValueType() 是隐含的,非常危险。你可以明确表达,但我会完全消除它。
  • operator ValueType() 需要知道ValueType 的详细信息才能被创建。因此,如果 ValueType 尚未完全定义,您将收到有关不完整类型的编译器错误。同样,删除该方法可以消除此问题。
  • operator SharedPointer&lt;U&gt;()operator bool() 也是隐含的。首选explicit
  • 强烈考虑将assert 添加到所有使用sharedptr 的方法中,而不首先检查它是否为null
  • Raw() 通常被命名为 get()

现在,OrigTReleasestd::shared_ptr 做了一个有趣的技巧,其中 SharedData 具有继承性:

struct SharedData {
    std::atomic_uint count;
    virtual ~SharedData() {}
};
template<class OrigT>
struct SharedDataImpl {
    OrigT* data;
    ~SharedData() {delete data;}
};

由于相同数据的所有 shared_ptrs 都将指向相同的 SharedDataImpl,因此它们不必知道最派生的类。他们所要做的就是删除 SharedData 成员,它会自动正确地清理数据。这确实需要第二个数据指针:一个在SharedPointer 本身,一个在SharedData,但通常这不是问题。 (或virtual T* get() 方法)

【讨论】:

  • 在访问 ptr 或您的案例数据时,编译器是否知道如何取消引用它而不必取消引用两次?
  • @Silberling:不。您必须在SmartPointer 本身中拥有第二个data 指针,或者接受性能损失。我会推荐之前的,这就是为什么我写了SharedData 没有virtual T* get() 方法。
  • 我注释掉了“operator ValueType() const noexcept”和“template operator SharedPointer() const noexcept”,但它仍然会抱怨,因为如果类型不完整。 std::shared_ptr 在我尝试 SharedPointer 的地方工作得很好。
  • @Silberling:哪一行抱怨类型不完整?我没有看到任何其他需要完整类型的东西,至少要实例化类本身。完整的错误信息是什么,它在哪一行抱怨?是Construct 方法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-14
  • 2011-07-25
  • 1970-01-01
  • 2012-02-07
  • 2011-04-06
  • 2011-06-28
相关资源
最近更新 更多