实战c++中的智能指针unique_ptr系列-- unique_ptr与lambda的错误结合(尤其是捕获lambda中的unique_ptr)

lambda表达式是C++11新引入的东西,给我们带来了很多的方便,使得代码简洁明了。

但是当我们把unique_ptr和lambda表达式结合的时候,错误就往往会出现,而且是致命的。

直接看看下面的代码:

#include "stdafx.h"
#include 
#include 
#include 

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

int main(int argc, char* argv[])
{
     std::vector<std::unique_ptr>messages;

     for (int i = 0; i < 1000; i++) {
          std::unique_ptr testMess;
          messages.push_back(std::move(testMess));  
     }

     std::for_each(messages.begin(), messages.end(),
                [](std::unique_ptr testMess) {     
        // do something stupid
     });

   return 0;
}

但是不幸的是,这段代码编译就会产生错误,但也算是幸运的:

d:\program files (x86)\microsoft visual studio 14.0\vc\include\algorithm(24): error C2280:std::unique_ptr,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)”: 尝试引用已删除的函数

简单分析
我们在lambda表达式中使用的是按值传递;
按值传递就会产生副本,就会产生一个unique_ptr的copy;
但是我们知道的,这显然是错误。

解决方法很简单,就是按引用传递替代按指针传递:

#include 
#include 
#include 
#include 

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

int main(int argc, char* argv[])
{
    std::vector<std::unique_ptr>messages;

    for (int i = 0; i < 1000; i++) {
        std::unique_ptr testMess;
        messages.push_back(std::move(testMess));
    }

    std::for_each(messages.begin(), messages.end(),
        [](std::unique_ptr &testMess) {
        // do something stupid
    });

    return 0;
}

上面的内容只是算个开胃菜,如果我们想在lambda表达式中捕获unique_ptr,又会如何呢?

十分优雅的写下如下代码:

#include
#include
#include
int main()
{
    auto str = std::make_unique<std::string>("my string");
    auto lambda = [capturedStr = std::move(str)]{
        std::cout << *capturedStr.get() << std::endl;
    };
    lambda();
    return 0;
}

一切很完美,编译 运行 输出正确。

接下来,再干点事儿:

#include
#include
#include
int main()
{
    auto str = std::make_unique<std::string>("my string");
    auto lambda = [capturedStr = std::move(str)] {
        std::cout << *capturedStr.get() << std::endl;
        auto str2 = std::move(capturedStr);
        std::cout << *str2 << std::endl;
    };
    lambda();
    return 0;
}

恭喜你,编译错误。

原因为何呢?为什么 auto str2 = std::move(capturedStr);会错误呢?
这就是lambda表达式的知识了:
lambda表达式默认是const的,我们当然不能std::move一个const对象。

解决方法也很简单,就是加入关键字mutable
程序如下,运行完好:

#include
#include
#include
int main()
{
    auto str = std::make_unique<std::string>("my string");
    auto lambda = [capturedStr = std::move(str)] ()mutable {
        std::cout << *capturedStr.get() << std::endl;
        auto str2 = std::move(capturedStr);
        std::cout << *str2 << std::endl;
    };
    lambda();
    return 0;
}

你可能感兴趣的:(C++)