本文简要学习记录。
使用场景如下:
(1)c++标准库使用比如vector::push_back等这类函数时,会对参数的对象进行复制,连数据也会复制。这就造成了对象内存的额外创建,本来原意是想把参数push_back进去就可以了。
(2)c++11提供了std::move函数来把左值转换为xrvalue,而且新版的push_back也支持&&参数的重载版本,这时候就可以高效率地使用内存了。
使用前提:
(1)定义的类使用了资源并且定义了移动构造函数和移动赋值运算符。
(2)该变量即将不再使用。
c++11 中引入std::ref用于取某个变量的引用,这个引入是为了解决一些传参问题。
std::ref用于包装按引用传递的值
std::cref用于包装按const引用传递的值。
我们知道c++中本来就有引用的存在,为何c++11中还要引入一个std::ref呢?主要是考虑函数式编程(如:std::binding)在使用时,是对参数直接拷贝,而不是引用。
下面通过例子进行说明:
例子1:
#include
#include
void f(int &n1, int &n2, const int &n3)
{
std::cout << "In function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
++n1; // increments the copy of n1 stored in the function object
++n2; // increments the main()'s n2
// ++n3; // compile error
}
int main()
{
int n1 = 1, n2 = 2, n3 = 3;
std::function bound_f = std::bind(f, n1, std::ref(n2), std::cref(n3));
n1 = 10;
n2 = 11;
n3 = 12;
std::cout << "Before function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
bound_f();
std::cout << "After function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
return 0;
}
运行结果为:
上述代码在执行std::bind后,在函数f()中n1的值仍然为1。n2和n3改成了修改的值,
说明std::bind使用的是参数的拷贝而不是引用,因此必须显示利用std::ref来进行引用绑定。
具体std::bind不使用引用,可能确实有一些需求,使得c++11的设计者认为默认应该采用拷贝,如果使用者有需求,加上std::ref即可。
例子2:
#include
#include
void threadFunc(std::string &str, int a)
{
str = "change by threadFunc";
a = 13;
}
int main()
{
std::string str("main");
int a = 9;
std::thread th(threadFunc, std::ref(str), a);
th.join();
std::cout << "str = " <
输出:
从输出结果可以看出:和std::bind类似,多线程的std::thread也是必须显式地通过std::ref来绑定应用进行传参,否则参数的引用声明是无效的。
可将std::bind函数看作是一个通用的函数适配器。它接受一个可调用对象生成一个新的可调用对象来“适应”原对象的参数列表。
std::bind将可调用对象与其参数一起进行绑定,绑定后的结果可以使用std::function保存。
到 bind 的参数被复制或移动,而且决不按引用传递,除非包装于std::ref或std::cref。
std::bind主要有以下两个作用:
3.1、std::bind绑定普通函数
double my_divide (double x, double y)
{return x/y;}
auto fn_half = std::bind (my_divide,_1,2);
std::cout << fn_half(10) << '\n';
3.2、std::bind绑定一个成员函数
struct Foo {
void print_sum(int n1, int n2)
{
std::cout << n1+n2 << '\n';
}
int data = 10;
};
int main()
{
Foo foo;
auto f = std::bind(&Foo::print_sum, &foo, 95, std::placeholders::_1);
f(5); // 100
}
bind绑定类成员函数时,第一个参数表示对象的成员函数的指针,第二个参数表示对象的地址。
必须显示的指定&Foo::print_sum,因为编译器不会将对象的成员函数隐式转换成函数指针,所以必须在Foo::print_sum前添加&;
使用对象成员函数的指针时,必须要知道该指针属于哪个对象,因此第二个参数为对象的地址 &foo;
转载自:std::move ,std::ref,std::bind - 知乎 (zhihu.com)