左值引用

左值引用是指针的语法糖,和指针作用相同,两者的区别主要是:

  • 引用必须立即初始化,但是指针可以先初始化为空指针

  • 对引用取地址得到的是原变量的地址,对指针取地址得到的是指针变量的地址

  • 对引用 sizeof 得到的是对象的大小。对指针 sizeof 得到的是指针的宽度

  • 引用无法更换指向目标,但是指针可以

如果一个引用指向的对象已经销毁,那么这个引用就变成了一个悬空引用。访问它是未定义行为。

移动语义

移动语义可以用来转移对象的所有权,这一操作是通过移动构造函数实现的。std::move 通过将对象强转转为右值引用的形式请求调用移动构造函数,从而触发移动语义。

移动构造函数的目的是转移对象所有权。所有权转移的实现本质上是通过 memmove 和 memset 实现的。

如果是使用右值赋值操作,则还需要释放自己持有的资源。

移动语义对于 POD 对象没有意义。

- 移动语义是为了管理所有权而不是提高性能。

完美转发

现在假设有这样一个工厂函数:它构造指定类型,并返回其智能指针。现在假设此对象只有一个参数,那么代码假设是这样:

template<class T, class A1>
std::shared_ptr<T> factory(const A1& a1) {
    return std::shared_ptr<T>(new T(a1));
}

调用方式为:

std::shared_ptr<A> p = factory<A>(5);

但是如果 A 的构造函数需要的参数是非 const 引用呢?这种情况下就会导致编译错误。

因此修改后的代码为:

template<class T, class A1>
std::shared_ptr<T> factory(A1& a1) {
    return std::shared_ptr<T>(new T(a1));
}

现在 const 版本和非 const 版本都能用了。

请注意:使用这种方式可以解决参数转发时的 cv 限定类型。事实上,这正是当今转发应用程序的编码方式(例如 std::bind )

但是又带来一个新问题:无法传递右值,下述这样的代码无法编译:

std::shared_ptr<A> p = factory<A>(5); // 错误
A* q = new A(5); // 允许

因此最佳的方式是使用右值引用作为参数:

template<class T, class A1>
std::shared_ptr<T> factory(A1&& a1) {
    return std::shared_ptr<T>(new T(a1));
}
Last moify: 2024-11-22 02:16:03
Build time:2025-07-18 09:41:42
Powered By asphinx