shared_ptr<interface> 实例中的重载 -> 箭头运算符,接口中没有纯虚拟析构函数

Overload -> arrow operator in shared_ptr<interface> instance with no pure virtual destructor in interface

我正在尝试重载 -> 运算符以最终执行以下代码:

MyInterface *myInstance = (MyInterface *)(new A());
myInstance->Toggle(); //this works wonderfully

std::shared_ptr<Wrapper<MyInterface>> sharedPtrWrapper = std::make_shared<Wrapper<MyInterface>>(myInstance);

//the next line doesn't compile, I would like to achieve something like this, but even 
//sharedPtrWrapper.get()->Toggle(); 
//would be nice to achieve, is this possible? 
sharedPtrWrapper->Toggle(); 

//this works:
sharedPtrWrapper->operator->()->Toggle();

注意:我无法控制MyInterface,无法实现纯虚析构函数。

这是我尝试过的(下面的代码运行):

#import <memory>
#import <iostream>

struct MyInterface {
    virtual bool Toggle() = 0;
};

class A : public MyInterface {
public:
    bool Toggle() {
        stateEnabled = !stateEnabled;
        std::cout<<"current state " << stateEnabled << std::endl;
        return true;
    }
private:
    bool stateEnabled = false;
};

template <typename T>
class Wrapper {
private:
    T *unsafePointer = nullptr;
public:
    Wrapper<T>()
    { }

    T *operator->() const {
        return unsafePointer;
    }
    T *getInner() {
        return unsafePointer;
    }
    Wrapper<T>(T *stuff) {
        unsafePointer = stuff;
    }

    ~Wrapper<T>() {}
};

int main(int argc, const char * argv[]) {
    MyInterface *myInstance = (MyInterface *)(new A());
    myInstance->Toggle();


    Wrapper<MyInterface> wrapperS(myInstance);
    wrapperS->Toggle();


    std::shared_ptr<Wrapper<MyInterface>> sharedPtrWrapper = std::make_shared<Wrapper<MyInterface>>(myInstance);
    sharedPtrWrapper->operator->()->Toggle();
    sharedPtrWrapper.operator->()->operator->()->Toggle();

    sharedPtrWrapper.get()->operator->()->Toggle();

    (*sharedPtrWrapper).operator->()->Toggle();

    return 0;
}

输出:

current state 1
current state 0
current state 1
current state 0
current state 1
current state 0
Program ended with exit code: 0

重申一下: 此代码无法编译:

sharedPtrWrapper->Toggle(); 

如何编译?

Edit :我正在使用包装器,因为我无法控制 MyInterface,我从库中获取它,shared_ptr<MyInterface> mySharedPointer = std::make_shared<MyInterface>(myInstance); 也无法编译,因为上面提到的接口缺少纯虚拟析构函数。

Edit2:伪代码中的示例库用法:

void firstcallbackFromLib(Framework *framework) {
    MyInterface *myInstance = framework->getInstance();

    {
        Wrapper<MyInterface> wrapperS(myInstance);
        std::shared_ptr<Wrapper<MyInterface>> sharedPtrWrapper = std::make_shared<Wrapper<MyInterface>>(wrapperS);
        //assign sharedPtrWrapper and framework to static instances
    }
}
void myFunction() {
    sharedPtrWrapper->Toggle(); //this doesn't work, this is what i'm trying to achieve
    sharedPtrWrapper->operator->()->Toggle(); //this ugly thing works

}
void lastUninitCallbackFromLibrary() {
    MyInterface *p = sharedPtrWrapper.get()->getInner();
    framework->releaseInterface(p);
    //etc
}

我对这个问题感到困惑。为什么包装器 class 什么都不做?

如果你想把一个 class 放在共享指针中,但在销毁时做一些不常见的事情:比如,调用执行销毁的 dll 函数,做一些预处理,执行文件关闭而不是删除,或者什么都不做如果这就是你想要的。然后你可以简单地在共享指针实例化时指定它: https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr - 参见构造选项 5。

问题是,shared_ptr 表现得像一个指针,Wrapper 也是如此。总之,您的代码的行为类似于指向指针的指针。简而言之,您可以调用 (*sharedPtrWrapper)->Toggle(); 而不是可憎的 sharedPtrWrapper->operator->()->Toggle();.

不过要小心:目前还不清楚所有这一切应该实现什么,因为示例代码只是您实际代码的抽象。因此,也许将转发 Toggle() 方法放入 class Wrapper 中会更优雅,但根据此处提供的信息无法判断。

sharedPtrWrapper->Toggle(); 无法编译,因为 operator-> 链接规则解释得很好 in this answer。原则上:如果您的对象不是指针,则递归调用 operator-> ,如果它是指针,则执行成员访问。现在 std::shared_ptr 已重载 operator-> 以访问保存在内部的原始 Wrapper<MyInterface>* 指针,当它应用于它时,它会尝试访问不存在的 Toggle

为清楚起见,请注意此代码也不会编译:

Wrapper<MyInterface>* wrapper = new Wrapper<MyInterface>(myInstance);
wrapper->Toggle();

不过您可以这样做:

(*sharedPtrWrapper)->Toggle();

您根本不需要包装器。

shared_ptr<MyInterface> mySharedPointer = std::make_shared<MyInterface>();

不会工作,因为 MyInterface 是一个抽象 class。但是,就像你可以做的那样

MyInterface *myInstance = new A();

要有一个指向具体派生对象的MyInterface *,您可以使用

std::shared_ptr<MyInterface> sharedPtr = std::make_shared<A>();

获取指向具体派生对象的std::shared_ptr<MyInterface>。然后,您可以使用 sharedPtr 访问 Toggle 就像

sharedPtr->Toggle();

你可以看到在这个 live example

中工作

使用:

struct CleanupMyInterface {
  SomeTypeFromLib* somePointerFromLib = nullptr;
  void operator()( MyInterface* ptr ) const {
    if (somePointerFromLib && ptr)
      somePointerFromLib->releaseInterface(ptr);
  }
};
std::shared_ptr<MyInterface> sharedPtr( CreateAnInstanceOfAFromLibrary(), CleanupMyInterface{somePointerFromLib} );

shared_ptr 有类型擦除破坏,不需要虚拟析构函数。