在不传递所有权的情况下重新分配函数中的智能指针?

Reassign a smart pointer in a function without passing ownership?

背景

使用普通指针,我可以做类似下面的事情

void conditional_reassign(MyClass* ptr)
{
    if (my_condition)
    {
        delete ptr;
        ptr = new MyClass(new_param);
    }
}

而且我可以像下面这样传入我想改变的指针

MyClass* ptr = new MyClass(old_param);
conditional_reassign(ptr);

我希望用 std::unique_ptr 重新实现它。这是我想出的

std::unique_ptr<MyClass> conditional_reassign2(std::unique_ptr<MyClass> ptr)
{
    if (my_condition)
    {
        ptr = std::make_unique<MyClass>(new_param);
    }
    return std::move(ptr);
}

我会这样称呼它

std::unique_ptr<MyClass> ptr = make_unique<MyClass>(old_param);
ptr = std::move(conditional_reassign2(std::move(ptr)));

问题

我对这行的冗长不太满意

ptr = conditional_reassign2(std::move(ptr));

有没有办法实现 conditional_reassign2 以便我可以用类似于 conditional_reassign(ptr)

的方式调用它

编辑

我应该注意

的一个主要问题
ptr = std::move(conditional_reassign2(std::move(ptr)));

是不管my_condition会破坏ptr指向的原始对象(见

您可以定义 conditional_reassign2() 函数来获取 std::unique_ptr by reference 而不是 by value

void conditional_reassign2(std::unique_ptr<MyClass>& ptr)
{
    if (my_condition)
    {
        ptr = std::make_unique<MyClass>(new_param);
    }
}

这样函数可以直接修改传递的实例,不需要转移所有权。

假设 ptr 是一个 std::unique_ptr<MyClass>,那么在这种情况下调用 conditional_reassign2() 将是:

conditional_reassign2(ptr);

要么你需要通过引用传递指针

void conditional_reassign2(std::unique_ptr<MyClass>& ptr) {...}

std::unique_ptr<MyClass> myPtr;
conditional_reassign2(myPtr);

或return指针,需要一次移动

std::unique_ptr<MyClass> conditional_reassign2(std::unique_ptr<MyClass> ptr) {...}

std::unique_ptr<MyClass> myPtr;
myPtr = conditional_reassign2(std::move(myPtr));

您也可以直接从函数 return ptr 而无需显式调用 move。

std::unique_ptr<MyClass> conditional_reassign2(std::unique_ptr<MyClass> ptr)
{
    if (my_condition)
        ptr = std::make_unique<MyClass>(new_param);
    return ptr;
}

您的第一个示例没有按照您的预期进行。由于 ptr 是按值传递的,因此不会修改调用者的指针。所以如果my_conditiontrue,调用者有一个指向已删除对象的指针,而新创建的对象所在的地址在函数returns之后丢失了。

这是您修复的第一个示例(参数现在是对指针的引用):

void conditional_reassign((MyClass*)& ptr)
{
    if (my_condition)
    {
        delete ptr;
        ptr = new MyClass(new_param);
    }
}

要使用 unique_ptr,您也可以使用引用而不是 return 任何东西。这样就不需要处理 std::move

void conditional_reassign2(std::unique_ptr<MyClass>& ptr)
{
    if (my_condition)
    {
        ptr =  std::make_unique<MyClass>(new_param);
    }
}

你可以这样称呼它:

std::unique_ptr<MyClass> ptr = make_unique<MyClass>(old_param);
conditional_reassign2(ptr);

或者您可以使用 return/move 语义:

std::unique_ptr<MyClass> conditional_reassign(std::unique_ptr<MyClass> ptr)
{
    if (my_condition)
    {
        return std::make_unique<MyClass>(new_param);
    }

    return ptr;
}

并这样称呼它:

std::unique_ptr<MyClass> ptr = make_unique<MyClass>(old_param);
ptr = conditional_reassign2(std::move(ptr));