【问题标题】:Converting this to shared pointer and passing it as an argument to another C++ class将此转换为共享指针并将其作为参数传递给另一个 C++ 类
【发布时间】:2017-06-09 02:07:24
【问题描述】:

我正在使用以下框架编写代码:

class IFirstStep // abstract interface
{
public:
    virtual commonMethod1() = 0;
    ...
};

class FirstStepBase : public IFirstStep // Jobs common to all FirstStep's
{
public:
    FirstStepBase() {}
    commonMethod1() override;
    ...
protected:
    CommonMembers;
    void correctSettings()
    {
        somePreparations;
        auto smartPtr = static_cast<std::shared_ptr<IFirstStep>>(this);
        SecondStep secondStep(smartPtr);
        some calculations using secondStep;
        reassignment of some of commonMembers;
    }
};

class FirstStep1 : public FirstStepBase
{
public:
    FirstSiep1(bool fineTune)
    {
        commonMembers = initilizeSettings();
        if (fineTune)
            correctSettings();
    }
private:
    CommonMembers initilizeSettings() {calculate and assign commonMembers;}
};

class FirstStep2 : public FirstStepBase
...
class FirstStepN : public FirstStepBase
...

class SecondStep
{
public:
    SecondStep(std::shared_ptr<IFirstStep> & firstStep) : m_firstStep(firstStep) {}
    some methods which use firstStep and return some results;
    firstStep itself is not changed;
};

correctSettings() 被完美执行,纠正了 FirstStep1 的所有设置,但在 MS VS 调试器中在从正确设置() 退出时崩溃:

File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp
Line: 888
Expression: _CrtIsValidHeapPointer(block)

看起来问题是由强制转换引起的 - 即使在强制转换后执行退出,代码也会崩溃。 MS VS 编译器不接受其他类型的转换,包括指针转换。但是,如果将 correctSettings() 更改如下并将适当的构造函数添加到 FirstStepBase 中,则事情会完美运行

void correctSettings()
{
    std::shared_ptr<IFirstStep> smartPtr 
        = <std::make_shared<FirstStepBase>>(commonMembers);
    SecondStep secondStep(smartPtr);
    some calculations using secondStep;
    reassignment of some of commonMembers;
}

我将非常感谢解释为什么第一种方法会失败,是否可以在代码中使用 this 指针而不是生成额外的 FirstStepBase 对象?请假设无法更改 SecondStep 的接口。 谢谢。

【问题讨论】:

    标签: c++ pointers arguments this


    【解决方案1】:

    在您的第一种方法中,您的 this 只是一个原始指针,但您尝试将其转换为具有不同大小、不同结构的 `shared_pointer。

    要解决这个问题,您可以尝试使用boost::enable_shared_from_this,它可以让您从对象自己的函数中检索对象的共享指针。然后您不必构造另一个 FirstStepBase 对象。 你可以看这里boost_shared_from_this

    【讨论】:

    【解决方案2】:

    您不能将原始对象指针直接类型转换为 std::shared_ptr

    不过,您可以做的是从std::enable_shared_from_this 派生FirstStepBase,然后FirstStepBase 可以在需要时调用shared_from_this(),例如:

    class FirstStepBase : public std::enable_shared_from_this<FirstStepBase>, public IFirstStep // Jobs common to all FirstStep's
    {
        ...
        void correctSettings()
        {
            ...
            auto smartPtr = shared_from_this(); // <-- here
            SecondStep secondStep(smartPtr);
            ...
        }
    };
    

    这仅在 FirstStep... 对象开始由 std::shared_ptr 管理时才有效,因此请确保在创建 FirstStep... 对象时始终使用 std::shared_ptr

    另一方面,如果SecondStep 的寿命不超过其关联的FirstStep... 对象,那么就没有理由将std::shared_ptr&lt;IFirstStep&gt; 传递给它,只需传递一个原始IFirstStep* 指针即可:

    class SecondStep
    {
    private:
        IFirstStep *m_firstStep;
    public:
        SecondStep(IFirstStep *firstStep) : m_firstStep(firstStep) {}
        ...
    };
    

    只有当SecondStep 比所有FirstStep... 引用都更有效并且需要保持对象处于活动状态时,传递std::shared_ptr 才有意义。

    【讨论】:

    • 值得注意的是,当使用enable_shared_from_this 构造时,底层对象从一开始就实际上由std::shared_ptr 范式管理是至关重要的。不管怎样,这是一个非常方便的功能,我已经用过很多次了。
    • @WhozCraig:当你发表评论时,我实际上正在写那条笔记。
    • 谢谢。你建议的工作。我想我现在必须确保 FirstStep 的所有使用都将其实例化为“std::make_shared”而不是原始对象。这就是你在上一条评论中的意思吗?
    • @R.Cronneberg 是的,完全正确。
    • Remy Lebeau,@WhozCraig 感谢您的友好解释。
    【解决方案3】:

    “this”被转换为共享指针,但在这种情况下它不是原始指针

    【讨论】:

      猜你喜欢
      • 2012-06-05
      • 1970-01-01
      • 2016-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-28
      • 2016-07-20
      • 2012-01-24
      相关资源
      最近更新 更多