所谓的“现代C++”,就是指C++ 11标准之后的C++语言,与之相对应的是“经典C++”,也就是C++ 98/03标准的C++语言。Unreal Engine 4使用C++14标准开发,用到了很多现代C++的特性,而且它不使用标准库,这可能就需要我们对现代C++理解的更清晰一点。于是,打算把自己对于虚幻引擎中的现代C++编程的理解整理成博客,希望对Unreal C++开发的朋友有点帮助。这一系列博客主要还是讲现代C++的基础编程为主,并注重在虚幻引擎开发中的实用性。
首先,我们来聊一聊转移语义(Move Semantics),这是C++11标准中最重要的一个特性了。也许你在网上看过一些相关文章,往往前面先是大篇幅的讲解什么是“右值引用”,让人看的昏昏欲睡,然而“右值引用(Rvalue References)”只是一种底层的语言机制,基于它才能实现所谓的转移语义(Move Semantics)和完美转发(Perfect Forwarding)。在这里,咱们就直奔主题,从Why、What、How三个层面把转移语义搞明白,其中会用到“右值引用”,自然也能理解了。
转移语义解决什么问题?
“转移语义”真的不是啥玄妙的新技术,只是经典C++遗留问题的一个解决方案。在C++中默认使用值类型,值类型的变量之间只能执行“拷贝语义(Copy Semantics)”,而值拷贝对于那些管理着内部重量级资源的对象来说可能很昂贵,例如 std::vector 容器。
OK,咱们先不扯这些技术名词,来看个简单的例子吧。假设:我们要实现一个类,其内部管理一块内存,用来存储大量的数据。在C++中,一般会在构造的时候创建它们、在析构的时候要释放它们。经典C++执行对象复制的时候,需要通过自定义的拷贝构造函数和操作符来实现内部资源对象的复制。例如这样:
class MyString {
char* mData;
unsigned int mSize;
public:
MyString() : mData(nullptr), mSize(0) {
}
~MyString() {
if (mData) delete[] mData;
}
MyString(const MyString& other) {
if (other.mSize > 0 && other.mData) {
mData = new char[other.mSize];
mSize = other.mSize;
memcpy(mData, other.mData, mSize);
} else {
mData =