将原始指针传递给接受unique_ptr作为参数的函数

时间:2018-07-02 14:06:44

标签: c++ templates smart-pointers

我正在尝试编写一个函数,该函数接受来自Base的类的unique_ptr作为参数(以指示所有权转移)。我提出了以下代码:

#include <memory>
#include <type_traits>

class Base
{
  public:
    Base() {}
};

class Derived : public Base
{
  public:
    Derived() {}
};


void foo(std::unique_ptr<Derived> _data) {}

template <class T>
void boo(std::unique_ptr<T> _data) {
    static_assert(std::is_convertible<T*, Base*>::value,
                  "Only classes derived from Base can be used as "
                  "parameter for boo");
}


int main() { foo(new Derived); }

但是当我尝试编译它时,我得到了一个错误,并告诉我could not convert ‘(operator new(1ul), (<statement>, ((Derived*)<anonymous>)))’ from ‘Derived*’ to ‘std::unique_ptr<Derived>’是否使用foo,而当我使用boo时则相同(加上一些模板详细信息)。如果我正确理解了所有内容,那么就会知道没有std::unique_ptr<Derived>的构造函数可以接受Derived的指针。但是,当我查看unqiue_ptr构造函数的cppreference page时,发现有这样的构造函数(编号3-4)。

问题是:如何制作一个接受unique_ptr作为参数并使用原始指针调用的函数。

PS 。我试图编写一个接受unique_ptr的函数,因为我想表明该参数的所有权将被转移。如果您知道如何编写带有签名的函数,该签名可以清楚明确地表明所有权正在转让,那么我也将接受此答案。此函数既可以使用static_assert模板,也可以使用Base指针作为参数。

PS 。主要问题是如何制作foo(new Derived)。我知道我可以使用boo(std::make_unique<Derived>())(在这种情况下一切正常),但我也真的想知道为什么带有原始指针的示例不起作用,因为我不知道如何指示我正在“窃取”原始指针的所有权。

PS 使用示例(带有原始指针)(无效

Derived* derived_1 = new Derived;
// Do something with derived_1
boo(derived_1); // Pass to function and don't worry about `delete`
                // because you know that ownership has been
                // transferred and no longer is your concern

并带有智能指针

void foo_2(std::unique_ptr<Derived>& _data) {
     boo(std::move(_data)); 
}

std::unique_ptr<Derived> derived_2 = std::make_unique<Derived>();
// Do something with derived_2
foo(std::move(derived_2)); // Have to use `std::move`
                           // or
foo_2(derived_2);

第二个(省去了对新功能的需求)并不像第一个那么简单(尽管我应该承认相差并不大(也许是2次打字))

2 个答案:

答案 0 :(得分:8)

重载3和4在这里不适用。他们的签名是

unique_ptr( pointer p, /* see below */ d1 ) noexcept;

unique_ptr( pointer p, /* see below */ d2 ) noexcept;

,它们采用第二个参数,即自定义删除器。唯一适用的重载为2,即

explicit unique_ptr( pointer p ) noexcept;

由于将其标记为显式,因此不会将指针隐式转换为unique_ptr。这是一个安全问题,将其明确表示是正确的。如果不是explicit,那么

void foo(std::unique_ptr<int> _data) {}

int main()
{
    int bar;
    foo(&bar);
}

可以编译,但这将是未定义的行为,因为_data会在foo末尾销毁指针时尝试删除该指针。

答案 1 :(得分:1)

您必须明确进行转化:

int main()
{
    Derived* d = nullptr;
    BadInterface(&d); // mainly d = new Derived(..);
    foo(std::unique_ptr<Derived>(d));
}

为您提供一种内胆包:

foo(std::unique_ptr<Derived>(new Derived));
相关问题