在WebRTC的源码中有如下函数:

1
2
3
4
template <typename T>
std::unique_ptr<T> WrapUnique(T* ptr) {
return std::unique_ptr<T>(ptr);
}

该函数本身不复杂,重点在于它直接返回了一个std::unique_ptr,据我所知std::unique_ptr是不能够直接拷贝构造的,如:

1
2
std::unique_ptr<std::string> s1(new std::string("123"));
std::unique_ptr<std::string> s2 = s1; // ERROR

而且WrapUnique经过单步调试,整个函数的执行过程只有执行了一次std::unique_ptr构造。按照我的理解,至少要执行1次构造,2次拷贝构造的。那么WrapUnique为什么可以做到了?

结论是:C++编译器对匿名变量做了优化,编译器发现有变量来接收匿名变量,则直接将匿名变量的初始化过程放到接收该匿名变量的对象身上去,免去了后面的拷贝构造的过程。

如下测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
using namespace std;


class Apple {
public:
Apple() {
id_ = 0;
cout << "Apple()" << endl;
}

Apple(int id) {
id_ = id;
cout << "Apple(" << id_ << ")" << endl;
}

Apple(const Apple &a) {
id_ = a.id_;
cout << "Apple(const Apple &a)" << endl;
}

Apple& operator=(const Apple &that) {
id_ = that.id_;
cout << "Apple& operator=(const Apple &that)" << endl;
}

~Apple() {
cout << "~Apple()" << endl;
}
private:
int id_;
};

Apple WrapApple(int id) {
return Apple(id);
}


int main() {
Apple apple = WrapApple(666);

return 0;
}

不考虑匿名变量的优化,我们猜测执行过程的输出是:

1
2
3
Apple(666)
Apple(const Apple &a)
Apple(const Apple &a)

但实际执行结果是:

1
Apple(666)

编译器直接对apple对象进行初始化,省去了2次拷贝构造的过程。

WebRTC中的WrapUnique函数就是利用这个原理。