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

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

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

直接看看下面的代码:

#include "stdafx.h"
#include <memory>
#include <vector>
#include <algorithm>

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

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

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

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

   return 0;
}

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

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

简单分析

我们在lambda表达式中使用的是按值传递;

按值传递就会产生副本,就会产生一个unique_ptr的copy;

但是我们知道的,这显然是错误。

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

#include <iostream>
#include <memory>
#include <vector>
#include <algorithm>

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

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

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

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

    return 0;
}

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

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

#include<iostream>
#include<memory>
#include<string>
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<iostream>
#include<memory>
#include<string>
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<iostream>
#include<memory>
#include<string>
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;
}
时间: 2024-08-25 02:47:50

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

COCOS2D-X中的智能指针

Cocos2d-x中所有内存管理方式的基础是引用计数,动态分配一个Ref对象后其引用计数为1,并通过retain和release来增持和减少其引用计数.引用计数本身并不能帮助我们进行内存管理. 为了正确地释放对象的内存,Cocos2d-x使用Objective-C里面的自动回收池的机制来管理对象内存的释放.Autorelease有点类似于一个共享的"智能指针",该"智能指针"的作用域为一帧,该帧结束后,它将释放自己的引用计数,此时,如果该对象没有被其他"共

C++中的智能指针

众所周知.C++中对堆内存的申请与释放全然由用户来控制,这就造成用户在使用的时候常常造成内存泄漏.野指针.反复释放等常见的挂掉问题,所以我们有必要提供一套机制.使得用户仅仅需申请对应的内存,不用管释放的问题,事实上这属于著名的RAII(Resource Acquisition Is Initialization)技术 .在C++中这样的技术称作"智能指针",C++中的智能指针技术越来越受到广泛应用.以下简要介绍下智能指针. 从以上描写叙述中能够看出,我们须要提供一套内存显式申请与隐式释

Android系统篇之----Android中的智能指针

一.前言 今天我们开启Android系统篇的文章了,其实一直想弄,只是之前一直没有太多深入的了解,最近又把这块拿出来好好看了一下,所以想从新梳理一下,来看看Android中的这块知识,首先我们今天来看一下:Android中的智能指针的概念,为什么说先看一下智能指针这个知识呢?因为我们在看Android源码的时候,会发现几乎好多地方都用到了这个东东,所以我们在介绍后面的知识点,先来看看这个吧. 二.问题 那么Android中的智能指针是个什么东西呢?我们知道Android用的Java语言开发的,J

Boost中的智能指针(转)

这篇文章主要介绍 boost中的智能指针的使用.(转自:http://www.cnblogs.com/sld666666/archive/2010/12/16/1908265.html) 内存管理是一个比较繁琐的问题,C++中有两个实现方案: 垃圾回收机制和智能指针.垃圾回收机制因为性能等原因不被C++的大佬们推崇, 而智能指针被认为是解决C++内存问题的最优方案. 1. 定义 一个智能指针就是一个C++的对象, 这对象的行为像一个指针,但是它却可以在其不需要的时候自动删除.注意这个“其不需要的

OSG中的智能指针

在OpenSceneGraph中,智能指针(Smart pointer)的概念指的是一种类的模板,它针对某一特定类型的对象(即Referenced类及其派生类)构建,提供了自己的管理模式,以避免因为用户使用new运算符创建对象实例之后,没有及时用delete运算符释放对象,而造成部分内存空间被浪费的后果,也就是所谓的内存泄露错误. 由于OSG中与场景图形有关的大多数类均派生自Referenced类,因此OSG大量使用了智能指针来实现场景图形节点的管理.智能指针的使用为用户提供了一种自动内存释放的

ATL和vc++中的智能指针(分别是CComPtr和_com_ptr_t)

一.智能指针的概念 智能指针是一个类,不是指针,智能指针在所包含的指针不再被使用时候会自动释放该所包含指针所占用的系统资源,而不用手动释放. 原理:智能指针封装了包含指针的AddRef()函数和Release()函数,且在该类不被需要的时候在析构函数里调用包含指针的Release()函数释放包含指针的资源.因此实质是利用类的析构达到调用包含指针的Release()函数的目的. 二.VC++中的智能指针:_com_ptr_t _com_ptr_t实质是一个类模板.使用它时需要提供三个参数:接口的名

【FICO系列】SAP FICO 凭证错误:BKPFF$PRDCLN800在FI中达到的项目最大编号

公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[FICO系列]SAP FICO 凭证错误:BKPFF$PRDCLN800在FI中达到的项目最大编号 前言部分 大家可以关注我的公众号,公众号里的排版更好,阅读更舒适. 正文部分 行项目达到了999最大编号 sap提供了note解决方案 欢迎到群里下载note 也可以关注我的公众号了解 原文地址:https://www.cnblogs.com/S

实战c++中的智能指针unique_ptr系列-- unique_ptr的operator=、operator bool、reset、swap、get等介绍

既然打算把unique_ptr写一个系列,就要详尽一点,有些内容也许在vector的时候有个涉及,但是现在还是再谈论一番. 我们要把unique_ptr看做一个类,废话了,它当然是一个类.所以这个类肯定也重载了赋值运算符,即operator=.现在就开始看看operator=在unique_ptr中的使用: 官方描述如下: move assignment (1) unique_ptr& operator= (unique_ptr&& x) noexcept; assign null

实战c++中的智能指针unique_ptr系列-- 使用std::unique_ptr代替new operator(错误:‘unique_ptr’ is not a member of ‘std’)

写了很多篇关于vector的博客,其实vector很便捷,也很简单.但是很多易错的问题都是vector中的元素为智能指针所引起的.所以决定开始写一写关于智能指针的故事,尤其是unique_ptr指针的故事. 这是个开始,就让我们使用std::unique_ptr代替new operator吧! 还是用程序说话: #include<iostream> int main() { while (true) int *x = new int; } 看下任务管理器中的内存: 此时使用智能指针unique