gpt4 book ai didi

c++ - 在将 unique_ptr 移入我的基类构造函数之前,如何从 unique_ptr 中提取原始指针

转载 作者:行者123 更新时间:2023-12-01 19:22:17 25 4
gpt4 key购买 nike

我有一个非常具体的需求,需要访问特定于派生类的功能,我在构建包含类时在 unique_ptr 中获得了该派生类的实例。然后,该包含类必须将其基类的 unique_ptr 上转型移动到包含类的基类构造函数,最后在该包含类的基类中将其所有权移至该构造函数中。一些代码应该有帮助:

class MemberBase {};
class MemberDerived : public MemberBase { /*some public stuff not in MemberBase*/ };

class MainBase {
std::unique_ptr<MemberBase> member_;

public:
MainBase(std::unique_ptr<MemberBase> member) : member_(std::move(member)) {}
};

class MainDerived : public MainBase {
MemberDerived* member_derived_;
// This class proceeds to use MemberDerived-only functions

public:
// How to write the initialization list below?
MainDerived(std::unique_ptr<MemberDerived> member)
: MainBase(std::move(member)), member_derived_(member.get() /*nullptr!!*/) {}
};

忽略整体类设计问题(我知道与 MainDerived 中的 MemberDerived 特定函数的耦合并不理想;这是继承的代码,不能被在没有进行重大重构的情况下进行了更改),如何在将 unique_ptr 转发到 MainBase 之前捕获原始指针?

下面是我想到的一些想法以及为什么我认为它们不好。

  1. 向下 protected 访问器:
// Add this method to the protected section of MainBase:
MemberBase* MainBase::get_member() { return member_.get(); }

// Then downcast in MainDerived's c'tor
MainDerived::MainDerived(std::unique_ptr<MemberDerived> member)
: MainBase(std::move(member)), member_derived_(dynamic_cast<MemberDerived*>(get_member())) {}

这应该可以工作,但使用dynamic_cast(本身的主要缺点),当然,如果有人将传递给c'tor的类型更改为不是从MemberDerived派生的类型> 如果没有编译器的帮助,它将中断。

  • 传入指针两次:
  • // member and member_derived must point to the same object!
    MainDerived::MainDerived(std::unique_ptr<MemberDerived> member, MemberDerived* member_derived)
    : MainBase(std::move(member)), member_derived_(member_derived) {}

    除了制作一个相当难看的 c'tor 签名之外,用户可以很容易地为两个参数传递不同的指针,或者在调用 get 之前执行 move 。此外,用户现在被迫创建一个局部变量以将其传递到这两个地方。我有没有提到它很丑?

  • 使用辅助函数技巧翻转初始化顺序:
  • template <typename T>
    std::unique_ptr<T> ExtractPointer(std::unique_ptr<T> p, T** target) {
    *target = p.get();
    return std::move(p);
    }

    MainDerived::MainDerived(std::unique_ptr<MemberDerived> member)
    : MainBase(ExtractPointer(std::move(member), &member_derived_)) {}

    现在我实际上有点惊讶这没有产生任何警告/错误(gcc 5.4.0 with -Wall)。我的一部分喜欢这个,因为它看起来很安全,因为它很难被破坏,但 member_driven_ 的迂回初始化让我感到轻微的寒意。

    最佳答案

    你的第二个解决方案已经完成一半了。请注意,构造函数不需要是public。您可以将 2 个参数设为 private,并编写一个委托(delegate)给它的 1 个参数 public 构造函数。

    class MainDerived : public MainBase {
    MemberDerived* member_derived_;

    MainDerived(std::unique_ptr<MemberDerived> &member, MemberDerived *member_derived)
    : MainBase(std::move(member)), member_derived_(member_derived) { }

    public:
    MainDerived(std::unique_ptr<MemberDerived> member)
    : MainDerived(member, member.get()) { }
    };

    member 必须在 private 构造函数中通过引用获取,因为函数调用参数的求值顺序未指定。因此,您无法安全地将 memberpublic 构造函数移动到 private 构造函数的参数中,因为移动的顺序和get() 是未指定的,但我们需要 get() 在移动之前发生。最简单的修复方法是让 private 构造函数通过引用获取 member,这不会改变它。 (您还可以使用 {} 而不是 () 来强制执行计算顺序,但让您的代码依赖于如此微妙的构造并不是一个好主意。)

    关于c++ - 在将 unique_ptr 移入我的基类构造函数之前,如何从 unique_ptr 中提取原始指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59277928/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com