关于右值引用,为什么输出结果是这样?

运算符科技 2017-02-20 12:47:10
#include "stdafx.h"
#include <iostream>

using namespace std;

int g_constructCount = 0;
int g_copyConstructCount = 0;
int g_destructCount = 0;
struct A
{
A() { cout << "construct: " << ++g_constructCount << endl; }
A(const A& a) { cout << "copy construct: " << ++g_copyConstructCount << endl; }
~A() { cout << "destruct: " << ++g_destructCount << endl; }
void Output() { cout << "A" << endl; }
};
A GetA(int iType)
{
if (iType == 0)
{
A a1;
return a1;
}
else
{
A a2;
return a2;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
A&& a = GetA(0);
a.Output();

return 0;
}

VS2013,Release的输出结果:
construct: 1
copy construct: 1
destruct: 1
A
destruct: 2

本以只会调用一次构造函数,一次析构函数,但输出结果中出现了拷贝构造函数,是什么原因呢?
...全文
657 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
右值不是为了减少构造对象 右值不是为了减少构造对象 右值不是为了减少构造对象 是为了解决左值引用无法区分引用的值是右值还是左值,区分后就可以将右值的资源拿过来用减少资源分配
fefe82 2017-02-21
  • 打赏
  • 举报
回复
引用 18 楼 alicehyxx 的回复:
[quote=引用 17 楼 pengzhixi 的回复:] [quote=引用 16 楼 alicehyxx 的回复:] [quote=引用 13 楼 fefe82 的回复:] return 的地方有一个拷贝构造。
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
int g_constructCount = 0;
int g_copyConstructCount = 0;
int g_destructCount = 0;
struct A
{
    A() { cout << "construct: " << ++g_constructCount << endl; }
    A(const A& a) { cout << "copy construct: " << ++g_copyConstructCount << endl; }
    ~A() { cout << "destruct: " << ++g_destructCount << endl; }
    void Output() { cout << "A" << endl; }
};
A GetA(int iType)
{
    if (iType == 0)
    {
        A a1;
        return a1;
    }
    else
    {
        A a2;
        return a2;
    }
}
int _tmain(int argc, _TCHAR* argv[])
{
    A a = GetA(0);
    a.Output();
 
    return 0;
}
看以上的代码,输出的结果与 A&& a = GetA(0); 是一样的,如果return的地方有一个拷贝构造,那构造A a对象时,从函数返回值到生成a,是否该再一次调用拷贝构造?但结果却是只调用了一次。[/quote]返回值优化[/quote] 看来是了,VS2013是否有设置关闭NVO? 我本来以为通过右值引用,不会发生拷贝构造,看来一次拷贝构造是省不了了。[/quote] 拷贝构造不是通过右值引用省掉的,要用 copy ellision 来省掉。 不过 copy ellision 现在还不是强制的。
paschen 版主 2017-02-20
  • 打赏
  • 举报
回复
A GetA(int iType) 不是按右值引用返回的,返回时发生了复制(函数返回类型形式不取决于A&& a = GetA(0);这里的&&) 如果返回的是右值引用,函数形式需要是这种:A&& GetA(int iType)
fefe82 2017-02-20
  • 打赏
  • 举报
回复
return 的地方有一个拷贝构造。
  • 打赏
  • 举报
回复
A&& GetA(int iType)
{
    A a;
    return std::move(a);
}
这种代码是错的
运算符科技 2017-02-20
  • 打赏
  • 举报
回复
引用 10 楼 aqtata 的回复:
[quote=引用 6 楼 alicehyxx 的回复:] [quote=引用 4 楼 aqtata 的回复:] 第一,你贴的代码并没有"右值引用"。 第二,右值引用的意义主要在于避免字符串的拷贝,参考下面的例子。
#include "stdafx.h"
#include <iostream>

class A
{
public:
	A()
	{
		_s = new char[16]{ 0 };
		strcpy(_s, "Hello");
	}

	A(A&& a) noexcept
	{
		this->_s = a._s;
		a._s = nullptr;
	}

	virtual ~A()
	{
		delete _s;
	}

	void print() const { std::cout << _s << std::endl; }

private:
	char* _s = nullptr;
};

A GetA()
{
	A a;
	return a;
}

int main()
{
	auto a = GetA();
	a.print();

	system("pause");
	return 0;
}
A&& a = GetA(); 这不是右值引用?我就想通过这个由值引用延伸GetA()函数内部局部变量的生命周期。 你贴的代码,是Move语义的构造函数,这个我明白[/quote] sorry,理解错误。把GetA改改
A&& GetA(int iType)
{
	A a;
	return std::move(a);
}
[/quote] 这么改,就变为调用A类的Move构造函数了。 我是想通过由值引用延伸函数内部局部变量的生命周期,看来是不行了。
运算符科技 2017-02-20
  • 打赏
  • 举报
回复
引用 17 楼 pengzhixi 的回复:
[quote=引用 16 楼 alicehyxx 的回复:] [quote=引用 13 楼 fefe82 的回复:] return 的地方有一个拷贝构造。
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
int g_constructCount = 0;
int g_copyConstructCount = 0;
int g_destructCount = 0;
struct A
{
    A() { cout << "construct: " << ++g_constructCount << endl; }
    A(const A& a) { cout << "copy construct: " << ++g_copyConstructCount << endl; }
    ~A() { cout << "destruct: " << ++g_destructCount << endl; }
    void Output() { cout << "A" << endl; }
};
A GetA(int iType)
{
    if (iType == 0)
    {
        A a1;
        return a1;
    }
    else
    {
        A a2;
        return a2;
    }
}
int _tmain(int argc, _TCHAR* argv[])
{
    A a = GetA(0);
    a.Output();
 
    return 0;
}
看以上的代码,输出的结果与 A&& a = GetA(0); 是一样的,如果return的地方有一个拷贝构造,那构造A a对象时,从函数返回值到生成a,是否该再一次调用拷贝构造?但结果却是只调用了一次。[/quote]返回值优化[/quote] 看来是了,VS2013是否有设置关闭NVO? 我本来以为通过右值引用,不会发生拷贝构造,看来一次拷贝构造是省不了了。
pengzhixi 2017-02-20
  • 打赏
  • 举报
回复
引用 16 楼 alicehyxx 的回复:
[quote=引用 13 楼 fefe82 的回复:] return 的地方有一个拷贝构造。
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
int g_constructCount = 0;
int g_copyConstructCount = 0;
int g_destructCount = 0;
struct A
{
    A() { cout << "construct: " << ++g_constructCount << endl; }
    A(const A& a) { cout << "copy construct: " << ++g_copyConstructCount << endl; }
    ~A() { cout << "destruct: " << ++g_destructCount << endl; }
    void Output() { cout << "A" << endl; }
};
A GetA(int iType)
{
    if (iType == 0)
    {
        A a1;
        return a1;
    }
    else
    {
        A a2;
        return a2;
    }
}
int _tmain(int argc, _TCHAR* argv[])
{
    A a = GetA(0);
    a.Output();
 
    return 0;
}
看以上的代码,输出的结果与 A&& a = GetA(0); 是一样的,如果return的地方有一个拷贝构造,那构造A a对象时,从函数返回值到生成a,是否该再一次调用拷贝构造?但结果却是只调用了一次。[/quote]返回值优化
运算符科技 2017-02-20
  • 打赏
  • 举报
回复
引用 13 楼 fefe82 的回复:
return 的地方有一个拷贝构造。
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
int g_constructCount = 0;
int g_copyConstructCount = 0;
int g_destructCount = 0;
struct A
{
    A() { cout << "construct: " << ++g_constructCount << endl; }
    A(const A& a) { cout << "copy construct: " << ++g_copyConstructCount << endl; }
    ~A() { cout << "destruct: " << ++g_destructCount << endl; }
    void Output() { cout << "A" << endl; }
};
A GetA(int iType)
{
    if (iType == 0)
    {
        A a1;
        return a1;
    }
    else
    {
        A a2;
        return a2;
    }
}
int _tmain(int argc, _TCHAR* argv[])
{
    A a = GetA(0);
    a.Output();
 
    return 0;
}
看以上的代码,输出的结果与 A&& a = GetA(0); 是一样的,如果return的地方有一个拷贝构造,那构造A a对象时,从函数返回值到生成a,是否该再一次调用拷贝构造?但结果却是只调用了一次。
运算符科技 2017-02-20
  • 打赏
  • 举报
回复
引用 12 楼 akirya 的回复:
A&& GetA(int iType)
{
    A a;
    return std::move(a);
}
这种代码是错的
的确是错的,返回值应该就是A,只不过通过移动构造函数构造的
pengzhixi 2017-02-20
  • 打赏
  • 举报
回复
引用 8 楼 alicehyxx 的回复:
[quote=引用 3 楼 pengzhixi 的回复:] 那个if结构会影响到优化,出现这种选择结构的时候在优化临时变量的时候会有些影响
我本以为右值引用不受这个影响,RVO和NRVO受影响我知道,为啥右值引用也需要拷贝呢?[/quote]因为你没有move copy constructor
运算符科技 2017-02-20
  • 打赏
  • 举报
回复
引用 3 楼 pengzhixi 的回复:
那个if结构会影响到优化,出现这种选择结构的时候在优化临时变量的时候会有些影响
我本以为右值引用不受这个影响,RVO和NRVO受影响我知道,为啥右值引用也需要拷贝呢?
运算符科技 2017-02-20
  • 打赏
  • 举报
回复
引用 5 楼 cyfcsd 的回复:
调用GetA的时候会构造一个对象a1,这个对象是在GetA函数的栈内构建的,当函数返回时,必须要调用复制构造函数将这个对象“值拷贝”到函数外面(应该是主函数栈内),因为GetA的栈马上就要被释放了,必须在此之前将值复制出来,所以这里调用了一次复制构造函数,当然对应的也要调用两次析构函数了
如果对象a1不在if语句内部,GetA()函数改为: A GetA() A a1; return a1; } vs2013下,由于NRVO的存在,是不会调用拷贝构造的,就一次构造,一次析构
运算符科技 2017-02-20
  • 打赏
  • 举报
回复
引用 4 楼 aqtata 的回复:
第一,你贴的代码并没有"右值引用"。 第二,右值引用的意义主要在于避免字符串的拷贝,参考下面的例子。
#include "stdafx.h"
#include <iostream>

class A
{
public:
	A()
	{
		_s = new char[16]{ 0 };
		strcpy(_s, "Hello");
	}

	A(A&& a) noexcept
	{
		this->_s = a._s;
		a._s = nullptr;
	}

	virtual ~A()
	{
		delete _s;
	}

	void print() const { std::cout << _s << std::endl; }

private:
	char* _s = nullptr;
};

A GetA()
{
	A a;
	return a;
}

int main()
{
	auto a = GetA();
	a.print();

	system("pause");
	return 0;
}
A&& a = GetA(); 这不是右值引用?我就想通过这个由值引用延伸GetA()函数内部局部变量的生命周期。 你贴的代码,是Move语义的构造函数,这个我明白
flying_music 2017-02-20
  • 打赏
  • 举报
回复
调用GetA的时候会构造一个对象a1,这个对象是在GetA函数的栈内构建的,当函数返回时,必须要调用复制构造函数将这个对象“值拷贝”到函数外面(应该是主函数栈内),因为GetA的栈马上就要被释放了,必须在此之前将值复制出来,所以这里调用了一次复制构造函数,当然对应的也要调用两次析构函数了
pengzhixi 2017-02-20
  • 打赏
  • 举报
回复
那个if结构会影响到优化,出现这种选择结构的时候在优化临时变量的时候会有些影响
ri_aje 2017-02-20
  • 打赏
  • 举报
回复
返回值要复制到临时变量中,所以有两个变量。优化以后,应该能变成一个。
vnvlyp 2017-02-20
  • 打赏
  • 举报
回复
你这个拷贝构造函数并不是右值引用啊,另外右值引用拷贝是避免成员复制吧,对象本身要创建和销毁有什么问题?

64,637

社区成员

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

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