其他分享
首页 > 其他分享> > Lesson3

Lesson3

作者:互联网

New 和 delete

关键字 new(new operator)做了两件事情:

关键字 delete(delete operator)做了两件事情:

class A {
public:
	A() = default;
	~A() = default;
};

int main() {

	auto area = operator new(sizeof A);	// 分配内存
	auto p = new(area) A{};				// 构造

	p->~A();				// 析构
	operator delete(area);	// 释放内存
}

智能指针

回顾一下 make_human() 函数:

// 返回一个指向 Human 对象的指针
Human* make_human(Type type, const std::string& name) {

	if (type == Type::student) {
		return new Student{ name };
	}
	else {	// type == Type::teacher
		return new Student{ name };
	}
}

我们在函数内部使用 new operator 创建了 Human 对象(分配了内存)。如果对象没有销毁(内存没有释放),就会造成内存泄露。函数调用者得到了指向这块内存的指针,所以释放内存的责任就落在了函数调用者身上。如果函数调用层数很多,或者对象的创建和销毁距离很远,那么用户很可能忘记释放。

解决的方法是使用 RAII(Resource Acquisition Is Initialization,资源获取即初始化),让对象自己管理自己的内存。定义一个资源管理类,在构造的时候获取资源,在析构的时候释放资源。资源管理类定义在栈上,所以它的析构函数一般会自己调用,不需要用户调用。

class HumanPtr {
public:
	HumanPtr(Human* p) : p_{ p } {}
	~HumanPtr() { delete p_; }

private:
	Human* p_;
};

// 返回一个内部管理 Human 对象的 HumanPtr 对象
HumanPtr make_human(Type type, const std::string& name) {

	if (type == Type::student) {
		return new Student{ name };
	}
	else {	// type == Type::teacher
		return new Teacher{ name };
	}
}

int main() {

	auto p = make_human(Type::student, "mimi");
}	// 对象 p 被释放,其管理的 Human 对象也被释放

C++ 提供了智能指针,帮助我们管理资源:

一般使用 make_unique() 和 make_shared() 函数创建智能指针,下面两种写法是一样的:

auto p1 = std::unique_ptr<Student>{ new Student{"mimi"} };
auto p2 = std::make_unique<Student>("mimi");

注意,下面两种写法是不一样的:

auto p3 = std::shared_ptr<Student>{ new Student{"mimi"} };
auto p4 = std::make_shared<Student>("mimi");

在一些情况下,我们需要从对象返回一个指向自己的 shared_ptr。可以让类继承 enable_shared_from_this 类,在需要返回 shared_ptr 时使用 shared_from_this() 函数。注意,该类本身只能通过 shared_ptr 访问,外部不能直接访问构造函数,需要通过该类提供的 create() 函数获得 shared_ptr。有两种方法让构造函数对外部不可见:

#include <iostream>
#include <string>
#include <memory>
#include <boost/asio.hpp>
#include <absl/time/time.h>
#include <absl/time/clock.h>

using boost::asio::ip::tcp;

auto make_daytime_string() {
	return absl::FormatTime(absl::Now(), absl::LocalTimeZone());
}

class tcp_connection
	: public std::enable_shared_from_this<tcp_connection> {
	class token {
		token() = default;
		friend tcp_connection;
	};

public:
	// 外部无法访问私有的 token,也就无法调用构造函数
	tcp_connection(tcp::socket socket, token)
		: socket_{ std::move(socket) } {}

	// 外部只能使用 create() 创建 tcp_connection 对象
	static auto create(tcp::socket socket) {
		return std::make_shared<tcp_connection>(std::move(socket), token{});
	}

	void start() {
		message_ = make_daytime_string();
		boost::asio::async_write(
			socket_,
			boost::asio::buffer(message_),
			[self = shared_from_this()](boost::system::error_code, std::size_t) {}
		);
	}

private:
	tcp::socket socket_;
	std::string message_;
};

class tcp_serve {
public:
	tcp_server(boost::asio::io_context& io_context)
		: acceptor_{ io_context, tcp::endpoint{ tcp::v4(), 13 } } {
		start();
	}

private:
	void start() {
		acceptor_.async_accept(
			[this](boost::system::error_code ec, tcp::socket socket) {
				if (!ec) {
					tcp_connection::create(std::move(socket))->start();
				}
				start();
			}
		);
	}

	tcp::acceptor acceptor_;
};

int main( {
	try {
		boost::asio::io_context io_context;
		tcp_server server{ io_context };
		io_context.run();
	}
	catch (std::exception& e) {
		std::cerr << e.what() << '\n';
	}
}

Lamda 表达式

仿函数是可以像函数一样被调用的对象,它重载了 operator() 函数:

class Add {
public:
	template <typename T>
	T operator()(T a, T b) { return a + b; }
};

int main() {

	auto add = Add{};		// 定义 Add 对象
	auto sum = add(1, 2);	// 调用 add 的 operator() 函数
}

仿函数可以作为参数传递给 STL 的算法:

class Cmp {
public:
	template <typename T>
	T operator()(T a, T b) { return a > b; }
}

int main() {

	std::vector<int> nums{ 2,0,2,2 };
	std::sort(nums.begin(), nums.end(), Cmp{});
}

每次使用仿函数都要定义一个类,其实编译器可以帮我们完成,使用 lambda 表达式即可:

int main() {

	auto add = [](auto a, auto b) { return a + b; };	// 定义闭包
	auto sum = add(1, 2);	// 调用闭包的 operator() 函数
}

我们使用 lambda 表达式时,编译器会定义一个闭包类,然后定义相应的闭包对象:

class Add {
public:
	template <typename T1, typename T2>
	auto operator()(T1 a, T2 b) const { return a + b; }
};

int main() {

	auto add = Add{};
	auto sum = add(1, 2);
}

Lambda 表达式可以捕获外部的变量,有 3 种形式:

int main() {

	std::string s{ "abc" };

	auto func1 = [s] {};	// 值
	auto func2 = [&s] {};	// 引用
	auto func3 = [s = std::move(s)] {};	// 移动
}

编译器会定义一个闭包类,然后定义相应的闭包对象:

class Func1 {
public:
	Func1(const std::string& s) : s_(s) {}
	void operator()() const {}
private:
	std::string s_;
};

class Func2 {
public:
	Func2(std::string& s) : s_(s) {}
	void operator()() {}
private:
	std::string& s_;
};

class Func3 {
public:
	Func3(std::string&& s) : s_(s) {}
	void operator()() {}
private:
	std::string s_;
};

int main() {

	std::string s{ "abc" };

	auto func1 = Func1{ s };	// 值
	auto func2 = Func2{ s };	// 引用
	auto func3 = Func3{ std::move(s) };	// 移动
}

标签:Lesson3,std,string,auto,tcp,operator,shared
来源: https://blog.csdn.net/m0_37957950/article/details/122534214