首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

怎么让C++0x右值引用发挥威力

2012-10-18 
如何让C++0x右值引用发挥威力?右值引用号称将解决C++的临时对象问题,上代码:C/C++ code// 程序一,VC10,此

如何让C++0x右值引用发挥威力?
右值引用号称将解决C++的临时对象问题,上代码:

C/C++ code
// 程序一,VC10,此时如何通过右值引用,解决重新new内存的问题? 
// 由于MinGW 4.4使用引用计数,所以无法对比

#include <stdio.h>
#include <string>

std::string test(const std::string& str)
{
    printf("1: 0x%08x\n", str.c_str());
    std::string tmp(str);
    printf("2: 0x%08x\n", tmp.c_str());
    return std::move(tmp);
}

int main()
{
    printf("3: 0x%08x\n", test("右值引用测试!").c_str());
    return 0;
}

输出:
1: 0x0012ff40
2: 0x0012fedc
3: 0x0012ff24
如何做到第2次与第3次的内存地址一样?

C/C++ code
// 程序二,难道VC和GCC,对vector都使用了引用计数?// MinGW 4.4也是一样的结果#include <stdio.h>#include <vector>std::vector<int> test(const std::vector<int>& v){    printf("1: 0x%x\n", &v[0]);    std::vector<int> t(v);    t.push_back(88);    printf("2: 0x%x\n", &t[0]);    return t; // 与std::move(t);结果一样,为啥?    //return std::move(t);}int main(){    std::vector<int> v(1000); // 改变这个值的大小,将会看到v2[0]地址的变化,为啥?    v.push_back(2);    v.push_back(5);    v.push_back(9);    std::vector<int> v2 = test(v);    printf("3: 0x%x\n", &v2[0]);    for (int i = 0; i < 100; ++i)        v2.push_back(i);    printf("4: 0x%x\n", &v2[0]);    return 0;}

输出:
1: 0x4be880
2: 0x4c0088
3: 0x4c0088
4: 0x4c0088

为什么2、3、4的结果一样,都受main里的v的初始化大小的影响?
难道vector自己实现了类似右值引用这样的功能?

目前我能确定的是:VC的std::string从VC7开始,就不再使用引用计数;而MinGW(GCC)的std::string一直在使用引用计数。
是否右值引用的功能,需要库的支持:通过&&拷贝构造?
类似于:
C/C++ code
string(string&& s) { ... }

才能发挥威力?

[解决办法]
因为nrv等返回值优化规则。
[解决办法]
深度,关注!
[解决办法]
nrvo是有限的.
[解决办法]
程序员杂志专门有篇介绍这个
[解决办法]
探讨
在我的试验中发现nrv优化几乎是一定进行的,不受优化开关控制。

[解决办法]
gcc中,string有引用计数。
除此之外,所有的函数返回确定对象,都不生产临时对象,比如:

class T;

T create_T(...){
T x;
return x;
}

要想产生临时对象,要这样做:

T create_T(...){
if( ...){
T t1;
return t1;
}else{
T t2;
return t2;
}
}
[解决办法]
珍惜生命,远离c++0x

右值引用是一种新的类型,当然需要新的函数来配合了。


[解决办法]
而且右值引用并没有什么值得大题小作的。
gcc很久以前就注意这个问题了。


对于:

T createT();

T t = createT();
会调用3次构造函数(其中2次是拷贝),2次析构函数。
一次是createT()函数内那个局部变量, 出函数后析构了。
一次是函数返回值那个临时变量,赋值后析构了。
一个是最外面那个t。

如果用了右值引用, 也就是临时变量为右值引用,这时2次构造函数(一次右值拷贝),1次析构函数。
很郁闷的是,那个右值拷贝构造函数,没有默认的,必须手动提供一个(这点我弄得我很郁闷)。

而gcc的优化,是1次构造函数,无析构函数。

其中string的实现是最复杂的,利用了类似“写时复制”的技术。
------解决方案--------------------


若是我的KYString, c_str()方法要保证引用计数只能为1,所以需要重新分配缓冲区;若想都一样地址可以使用(char*)转换即可。

KYString类声明如下:

C/C++ code
#include<iostream>#include<algorithm>#include<vector>#include<string>using namespace std;void print(int x){cout<<x<<' ';}int main(){  vector<int> iter1,iter2;  for(int i=1;i<100;i++)  {  if(i%2==0)      iter1.push_back(i);  else       iter2.push_back(i);  }  for_each(iter1.begin(),iter1.end(),print);  cout<<endl;  for_each(iter2.begin(),iter2.end(),print);  cout<<endl;} 

热点排行