感慨C++0x!右值引用真强大!!

老邓 2009-10-27 12:44:02
编译器:VS2010beta2(VC10beta2),请注意test的返回值是std::string&&。
#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()
{
const std::string in("右值引用测试!");
printf("0: 0x%08x\n", in.c_str());
printf("3: 0x%08x\n", test(in).c_str());
return 0;
}

输出:
Microsoft (R) Program Maintenance Utility Version 10.00.21003.01
Copyright (C) Microsoft Corporation. All rights reserved.

0: 0x0012ff40
1: 0x0012ff40
2: 0x0012fefc
3: 0x0012fefc

通过2、3的输出可以发现对临时对象的返回,避免了对c_str()的拷贝!!

同样的代码,VS2010 beta1有警告:
Microsoft (R) Program Maintenance Utility Version 10.00.20506.01
Copyright (C) Microsoft Corporation. All rights reserved.

Main.cpp
Main.cpp(13) : warning C4172: returning address of local variable or temporary
NOTICE: 'Console' Build Finished.

而VS2010beta2一切正常。
不过,beta2编译后的程序体积要比beta1大很多。
beta1编译后是53.5KB,而beta2编译出来的是58.5KB。

期待VC10正式版!期待C++0x!!
...全文
1821 53 打赏 收藏 转发到动态 举报
写回复
用AI写文章
53 条回复
切换为时间正序
请发表友善的回复…
发表回复
aflyinghorse 2010-11-17
  • 打赏
  • 举报
回复
补充一下, 上面的代码用VS2010 professional 编译运行。
aflyinghorse 2010-11-16
  • 打赏
  • 举报
回复
// 这样修改就可以了, 输出结果显示了同样的地址
// 0x348588
// 28
// 0x348588
std::vector<char> UnicodeToAnsi(const wchar_t* buf)
{
int len = ::WideCharToMultiByte(CP_ACP, 0, buf, -1, NULL, 0, NULL, NULL);
if (len == 0) return std::move(std::vector<char>());

std::vector<char> utf8(len);
::WideCharToMultiByte(CP_ACP, 0, buf, -1, &utf8[0], len, NULL, NULL);

printf("0x%x\n", &utf8[0]);

return (utf8);
}

int main()
{
auto ret = UnicodeToAnsi(L"okokjfijeiljsiefjlsifjlisef");
cout << ret.size() << endl;
printf("0x%x\n", &ret[0]);

getchar();
return 0;
}
wangshiyang 2009-10-28
  • 打赏
  • 举报
回复
mark
独孤过儿 2009-10-28
  • 打赏
  • 举报
回复
继续讨论,再多点内容,这贴就可以建议加精了,呵呵
jackyjkchen 2009-10-27
  • 打赏
  • 举报
回复
围观老邓
mstlq 2009-10-27
  • 打赏
  • 举报
回复
围观,慢慢理解,消化中……
ryfdizuo 2009-10-27
  • 打赏
  • 举报
回复
学习一下!
光宇广贞 2009-10-27
  • 打赏
  • 举报
回复
[Quote=引用 44 楼 loaden 的回复:]
李博解释一下这个帖子:http://social.microsoft.com/Forums/zh-CN/visualcpluszhchs/thread/c7e8fc25-b449-4e72-a6ad-836bee09b2ab

为什么作者说的,我实现不了?
[/Quote]

……

我来晚了……

程姨都说明了。
美女她妈 2009-10-27
  • 打赏
  • 举报
回复
对了,补充说一下。

auto& 与 auto 这两种可是不一样的。不要指望 auto 一定能推导出引用出来。在所引博文中关于它到底是如何操作的有着详细的说明,为了保证为引用的话,请使用 auto& 的类型推导。

auto& ret = .....
美女她妈 2009-10-27
  • 打赏
  • 举报
回复
我怎么是马甲呢……我是程姨……

关于你 42 楼所说的,对比 33 楼差别在:

通过 DEBUG f11 追进去发现:

auto 的时候,这个类型推导,由于返回的是右值,在

http://blog.csdn.net/hikaliv/archive/2009/09/03/4515741.aspx

这篇博客中对于 auto 的使用已经提到了,它的类型推导只推导类型,这个右值引用的类型是 vector 的对像,而不是引用,所以你可以看到,它在这项赋值中调用了 vector 的移动构造函数!

所以就失败了。因为原来的栈对像已经析构了,它是无法满足 vector 的构造函数的需要的。

而使用 std::vector<char>& ret 成功是因为,指定了引用,便不会调用构造函数。

比如改成 auto& ret = 。。。 再试试?

这个是 auto 关键字使用的问题,详请见上面引用的博文。

sizeof 返回零不是右值引用的问题,是因为原来的栈变量已经被析构了。所以引用的是另一个东西。调试一下便会发现,这个 ret 引用的东西是 [0]() ……

地址当然就不一样了。因为栈变量已经归西了……

关于那个社区的链接……

哪个实现不了……我看了看就是为了区分一下什么时候用复制构造,什么时候用移动构造。

这个 shared_ptr 就是“偷对像”用的。曾见过有人用这个来人为的创造移动语义,不过在所引链接中好像不是这么一回事儿,而且返回这个智能指针出来本身是要进行它的复制的,这个先放一边,我想他主要想说的是 forward 这个东西。我在博文中与 move 一道,对其机理进行过分析。
ahao 2009-10-27
  • 打赏
  • 举报
回复
std::string& rs = test(in);
这个难道不应该是
std::string rs = test(in);
这样吗?
或者
std::string const& rs = test(in);
liyulun 2009-10-27
  • 打赏
  • 举报
回复
没接触过,看不懂
chenyu2202863 2009-10-27
  • 打赏
  • 举报
回复
呵呵,来感受新技术了
pcboyxhy 2009-10-27
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 loaden 的回复:]
引用 6 楼 fetag 的回复:
强大也没多大作用...这种代码写到实际项目中,不被骂死才怪呢,呵呵

现实的情况是:即使语言有很多new feature,或者写代码的人有什么高超的技法,但是很少允许用,因为要“兼

容”一些笨蛋,O(∩_∩)O哈哈~

嗯,我自己搞自己的,纯业余的。
将来会普及的!
写库时,可以极大的提高效率。
[/Quote]

我觉得难以普及,技术的使用总是保守又保守,很多公司Java1.4准备用到死
const在90年就引入C语言了,VLA数组,for中定义变量,都出现好多年了,可是没有一个是普及的
python3出来也很久了,还没看到往py3k迁移的迹象,大部分还抱着py2.5不放,甚至还有坚守py2.4的
C++新特性虽方便,却难以被项目接受,未来若干年里,估计只能是爱好,玩弄玩弄而已
老邓 2009-10-27
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 taodm 的回复:]
除非是编写通用库,否则这东西没啥用。
[/Quote]

不一定的。
即使是写一个函数,返回对象,还是返回对象的右值引用,效率上是不一样的。
不能完全依赖返回值优化:只要麻烦些,编译器就完蛋了。

这个文章介绍的很经典:http://social.microsoft.com/Forums/zh-CN/visualcpluszhchs/thread/c7e8fc25-b449-4e72-a6ad-836bee09b2ab

简介

C++0X是新一代C++标准的非官方名称。它将代替C++03成为C++最新的标准。C++0X对C++的核心语言以及标准库经进行了部分更新。C++0X完全兼容目前的C++标准。

在C++0X之中,语言本身添加了对于多线程的支持。一些细节得到了改进,例如支持统一初始化方式。对泛型编程的支持方面有了更边界的,同时对功能进行了改进。

核心语言功能
右值引用

在C++03中,临时变量(右值,出现在等号右侧的变量。另一种解释是引用值,没有实际地址的值)和const & type没有实际的差别。而在C++0X标准中添加了一种新的引用类型。叫做右值引用。它的定义类似于typename &&。另外右值引用提供了一种转移语义。

动机

右值引用的出现使得一些基础概念或者effective C++中表述的一些条目需要重新编写。那么来看看右值引用出现的动机是什么。

来看一个例子

std::vector实际上内部就是一个C类型数组,并且提供了一些内存和性能优化管理的机制。那么在现行的C++03标准中,当一个vector临时变量或者函数返回一个vector类型对象的时候。这里无可避免、毫无疑问的将会产生一个新的vector变量,并且将所有右值中的成员变量拷贝到这个临时变量中。(当然有些编译器具有NRV的优化功能,但是这种优化功能的执行情况和在复杂函数中的优化效果值得商榷)并且在拷贝结束后这个临时变量将被销毁,完成它短暂而又神圣的使命。

vector<SpecialClass> func()

{



return vect;

}

使用右值引用,在以上场景中std::vector的转移构造函数会被调用。转移的过程是把右值vector中指向C类型数组的指针直接拷贝到新的vector对象中。然后把右值中的数组指针置空。这样就省去了数组拷贝过程,并且删除一个空的临时变量不会产生大量的内存操作。

那么我们需要将返回值声明为std::vector<>&&,将会大幅简化内存操作。

vector<SpecialClass>&& func()

{



return std::move(vect);

}



右值引用不能引用一个左值对象,为了可以对指定的左值对象进行右值引用操作。标准库提供了std::move()函数。通过该函数可以获得指定对象的左值。

为自己的类定制右值引用构造函数

SpecialClass(SpecialClass&& rhs)

{



return *this;

}

当调用右值引用的类并没有定义右值引用构造函数时,默认的拷贝构造函数会被调用,并且参数会以const &的形式传入。

为了便于在模板中进行参数推到,标准库提供了std::forward()函数通过此函数可以保证传入参数的左右值性质不变

template <class T, class A1>

inline

shared_ptr<T>

factory(A1&& a1)

{

// If a1 is bound to an lvalue, it is forwarded as an lvalue

// If a1 is bound to an rvalue, it is forwarded as an rvalue

return shared_ptr<T>(new T(forward<A1>(a1)));

}



struct A

{

...

A(const A&); // lvalues are copied from

A(A&&); // rvalues are moved from

};



int main()

{

A a;

shared_ptr<A> sp1 = factory<A, A>(a); // "a" copied from

shared_ptr<A> sp2 = factory<A, A>(move(a)); // "a" moved from

}
冻结 2009-10-27
  • 打赏
  • 举报
回复
围攻
老邓 2009-10-27
  • 打赏
  • 举报
回复
李博解释一下这个帖子:http://social.microsoft.com/Forums/zh-CN/visualcpluszhchs/thread/c7e8fc25-b449-4e72-a6ad-836bee09b2ab

为什么作者说的,我实现不了?
老邓 2009-10-27
  • 打赏
  • 举报
回复
看来我要重新认识右值引用了。
虽然地址一样,但根本输出不了相应的值。
#include <windows.h>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

std::vector<char>&& UnicodeToAnsi(const wchar_t* buf)
{
int len = ::WideCharToMultiByte(CP_ACP, 0, buf, -1, NULL, 0, NULL, NULL);
if (len == 0) return std::move(std::vector<char>());

std::vector<char> utf8(len);
::WideCharToMultiByte(CP_ACP, 0, buf, -1, &utf8[0], len, NULL, NULL);

printf("0x%x\n", &utf8[0]);

return std::move(utf8);
}

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());
cout << tmp << endl;
return std::move(tmp);
}

int main()
{
std::vector<char>& ret = UnicodeToAnsi(L"okokjfijeiljsiefjlsifjlisef");
cout << ret.size() << endl;
printf("0x%x\n", &ret[0]);

const std::string in("test!");
printf("0: 0x%08x\n", in.c_str());

std::string& rs = test(in);
printf("3: 0x%08x\n", rs.c_str());
cout << rs << endl;
return 0;
}

输出:
0x392ef8
0
0x47ee98
0: 0x0012ff3c
1: 0x0012ff3c
2: 0x0012fef4
test!
3: 0x0012fef4

对rs的值输出是空白。晕了....
老邓 2009-10-27
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 fetag 的回复:]
强大也没多大作用...这种代码写到实际项目中,不被骂死才怪呢,呵呵

现实的情况是:即使语言有很多new feature,或者写代码的人有什么高超的技法,但是很少允许用,因为要“兼

容”一些笨蛋,O(∩_∩)O哈哈~
[/Quote]
嗯,我自己搞自己的,纯业余的。
将来会普及的!
写库时,可以极大的提高效率。
taodm 2009-10-27
  • 打赏
  • 举报
回复
除非是编写通用库,否则这东西没啥用。
加载更多回复(33)

64,683

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧