[C++ 学习笔记 3] std::make_shared 和 std::enable_shared_from_this

看 asio 范例 async_tcp_echo_server.cpp 的过程学习到不少东西。

//
// async_tcp_echo_server.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include "stdafx.h"
#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include "asio.hpp"

using asio::ip::tcp;

class session
	: public std::enable_shared_from_this<session>
	// UMU: enable_shared_from_this 是为了在类内部使用指向自己的 shared_ptr
{
public:
	session(tcp::socket socket)
		: socket_(std::move(socket))
	{
	}

	void start()
	{
		do_read();
	}

private:
	void do_read()
	{
		auto self(shared_from_this());
		// UMU: 捕获 this 是为了在 lambda 表达式里调用 do_write
		// UMU: 捕获 self 是为了在 lambda 表达式里引用它,增加引用计数器,防止未调用 lambda 函数前被释放
		socket_.async_read_some(asio::buffer(data_, max_length),
			[this, self](std::error_code ec, std::size_t length)
		{
			if (!ec) {
				do_write(length);
				// UMU
				std::cout.write(data_, length);
				std::cout << std::endl << std::endl;
			}
		});
	}

	void do_write(std::size_t length)
	{
		auto self(shared_from_this());
		asio::async_write(socket_, asio::buffer(data_, length),
			[this, self](std::error_code ec, std::size_t /*length*/)
		{
			if (!ec) {
				do_read();
			}
		});
	}

	tcp::socket socket_;
	enum { max_length = 1024 };
	char data_[max_length];
};

class server
{
public:
	server(asio::io_service& io_service, short port)
		: acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),
		socket_(io_service)
	{
		do_accept();
	}

private:
	void do_accept()
	{
		acceptor_.async_accept(socket_,
			[this](std::error_code ec)
		{
			if (!ec) {
				// UMU: std::move 是为了调用移动构造函数
				// UMU: std::make_shared 是为了包装 new 对象和 new shared_ptr,使这两个 new 都控制在 make_shared 内部,这样如果任何一个 new 失败,都可以正确释放
				std::make_shared<session>(std::move(socket_))->start();
			}

			do_accept();
		});
	}

	tcp::acceptor acceptor_;
	tcp::socket socket_;
};

int main(int argc, char* argv[])
{
	try {
		if (argc != 2) {
			std::cerr << "Usage: async_tcp_echo_server <port>\n";
			return 1;
		}

		asio::io_service io_service;
		server s(io_service, std::atoi(argv[1]));

		io_service.run();
	} catch (std::exception& e) {
		std::cerr << "Exception: " << e.what() << "\n";
	}

	return 0;
}

代码中的 self 只被 lambda 表达式捕获,在匿名函数体内部并没有被显式使用,但它是有被隐式引用到的,如果去掉对 self 的捕获,则在收到数据时,会发现 socket_ 已经失效了。

参考文章

  1. 《make_shared和shared_ptr的区别》http://www.tuicool.com/articles/F3u6jy
  2. 《std::enable_shared_from_this 有什么意义?https://www.zhihu.com/question/30957800
  3. 《c++11 条款21:尽量使用std::make_unique和std::make_shared而不直接使用new》http://blog.csdn.net/coolmeme/article/details/43405155

 

转载于:https://my.oschina.net/umu618/blog/819862

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值