是否可以使用非常量指针调用非常量函数,以及当两个 unique_ptrs 指向同一个对象时程序将如何运行?

Can a non-const function be called using a non-const pointer and how the program will behave when two unique_ptrs point to the same objec?

第一题:

现在我有两个 unique_ptrptrToBaseptrToDerived)指向同一个对象(由 make_unique 制作)。那么程序行为是未定义的还是如何销毁两个指针?

第二个:

指针as_const(ptrToDerived)是constatn。尽管 function2 是一个非常量函数

,但它是如何被调用的
#include <iostream>
#include<vector>

using namespace std;
class Base{

    public:
    virtual void function()const{
        cout<<"\n"<<__FUNCSIG__;
    }

    virtual~Base(){cout<<"\n"<<__FUNCSIG__;}
};




class Derived : public Base
{

    public:
    int var{9};

    virtual void function()const override{
        cout<<"\n"<<__FUNCSIG__<<"\nvar: "<<var;
    }
    void function1()const{
        cout<<"\n"<<__FUNCSIG__;
    }

    void function2(){
        cout<<"\n"<<__FUNCSIG__;
    }

    virtual~Derived(){cout<<"\n"<<__FUNCSIG__;}
};



int main()
{

    //ptr of type Base* pointing to an object of type of Derived 
    unique_ptr<Base> ptrToBase {make_unique<Derived>()};

    unique_ptr<Derived> ptrToDerived {dynamic_cast<Derived*>(ptrToBase.get())};
    if (ptrToDerived) ptrToDerived->function1();

    as_const(ptrToDerived)->function2();

    return 0;
}

So is the program behavior undefined or how will it work on destroying the two pointers?

是的,因为双重破坏,它有UB。不要这样做。

the pointer as_const(ptrToDerived) is constatn. how function2 can be called although it's a non-constant function

std::as_const 将使它成为 const std::unique_ptr<Derived> 而不是 std::unique_ptr<const Derived> 这就是调用 function2() 的原因。

另一方面,这将不起作用:

unique_ptr<const Derived> ptrToDerived{dynamic_cast<Derived*>(ptrToBase.get())};

ptrToDerived->function2();

可能的编译器输出:

source>:41:29: error: passing 'const Derived' as 'this' argument discards qualifiers [-fpermissive]

   41 |     ptrToDerived->function2();

您可以通过以下几种方式解决双删问题。

如果您知道您希望对象的生命周期由一个 unique_ptr 控制,您可以创建一个简单的 observer_ptr,它将保存一个指针但不会尝试销毁该对象:

// a deleter that will not delete
struct no_delete
{
    template<class P> 
    void operator()(P*) const noexcept
    {
        // nothing;
    }
};

template<class T> 
using observer_ptr = std::unique_ptr<T, no_delete>;

如果您希望对象的生命周期在最后一个指针超出范围时结束,并且您不知道哪个先超出范围,那么您需要 std::shared_ptr

https://godbolt.org/z/vrXzFT