将std :: unique_ptr分配给std :: function

时间:2019-01-29 11:20:37

标签: c++11

有一个自定义定义的映射,带有一个元素std :: function()>。 lambda代码正在运行,但是我不知道如何将其扩展为正常形式。代码如下。

class TestA{
public:
    TestA() {}
    ~TestA() {}

    TestA(const TestA &) {}

    static void print()
    {
        cout << __FUNCTION__ << endl;
        return;
    }
};

void testComplexMap1()
{

    typedef map<string, std::function<std::unique_ptr<TestA>()>> TempMap;
    TempMap m;
    // the lambda format code, it works
    //m.insert({ "TestA", []() {return std::unique_ptr<TestA>(new TestA());}});

    // I want to expand it, but failed.
    TestA *t = new TestA();
    //function<unique_ptr<TestA>()> fp(unique_ptr<TestA>(t));
    function<unique_ptr<TestA>()> fp(unique_ptr<TestA>(t)()); //warning here
    //m.emplace("TestA", fp);              // compile error here
}

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

fp未使用函数初始化,因此编译失败。

您可以像这样展开它:

TestA *t = new TestA();
std::unique_ptr<TestA> UT(t);   
auto func = [&]() { return move(UT);};
std::function<std::unique_ptr<TestA>()> fp(func);
m.emplace("TestA", fp);

请参见DEMO

答案 1 :(得分:0)

在C ++中,看起来像可能是声明的所有内容都被这样处理。 这意味着该行

function<unique_ptr<TestA>()> fp(unique_ptr<TestA>(t)());

解释为: fp是一个函数的声明,该函数返回一个std::function<unique_ptr<TestA>()>并期望一个名为t的参数,该参数是指向返回std::unique_ptr<TestA>并且不获取任何参数的函数的函数指针。 (这不是您想要的。)

这也意味着此行中的t与上一行中的t不同。

您必须传递fp这样实际上可以调用的东西:

std::unique_ptr<TestA> f() {    
    return std::make_unique<TestA>();
}

void testComplexMap1() {
    // ...
    function<unique_ptr<TestA>()> fp(f);
    m.emplace("TestA1", fp);  
}

如果要向地图添加将现有指针包装到unique_ptr中的函数,则需要一个仿函数:

class Functor {
public:
    Functor(TestA * a) : m_a(a) {}
    ~Functor() { delete m_a; }

    std::unique_ptr<TestA> operator()(){
        auto x = std::unique_ptr<TestA>(m_a);
        m_a = nullptr;
        return std::move(x);
    }

private:
    TestA * m_a;
};

void testComplexMap1() {
    //...
    TestA * t = new TestA();
    m.emplace("TestA", Functor(t));  
}

或带有捕获的lambda:

void testComplexMap1() {
    //...
    TestA * t = new TestA();
    m.emplace("TestA", [t](){ return std::unique_ptr<TestA>(t); });  
}

该lamda或多或少被翻译成Functor类之类的东西。但是,在每种情况下,您都必须非常小心:映射中将现有指针封装到std::unique_ptr中的函数可以并且应该仅被调用一次。

如果您不调用它们,则不会释放为t分配的内存。如果多次调用它们,则会得到std::unique_ptrnullptr(在我的Functor类变体中)或多个std::unique_ptr尝试管理相同的内存区域(在具有捕获变量的lambda中),第二个std::unique_ptr被删除后,该崩溃将崩溃。

简而言之:我建议不要编写这样的代码,而只将可多次调用的函数放在映射中。