从多个临时文件中创建引用
Creating a reference out of multiple temporaries
我正在尝试用户定义的文字(我相信是在gcc 4.7.1中引入的),但对临时性的工作方式感到困惑。
考虑以下代码:
#include <stdlib.h>
#include <iostream>
class Point
{
public:
Point(float x = 0, float y = 0, float z = 0)
:_x(x), _y(y), _z(z)
{
std::cout << "Constructorn";
}
~Point()
{
std::cout << "Destructorn";
}
Point& operator=(Point p)
{
std::cout << "Assignment opn";
return *this;
}
Point& operator+(const Point& p)
{
std::cout << "Returning ref: operator+n";
_x += p._x;
_y += p._y;
_z += p._z;
return *this;
}
void print() const
{
std::cout << "(" << _x << ", " << _y << ", " << _z <<")n";
}
protected:
float _x, _y, _z;
};
Point operator "" _x(const char* l)
{
float x = atof(l);
std::cout<<"literal _xn";
Point p(x);
return p;
}
Point operator "" _y(const char* l)
{
float y = atof(l);
std::cout<<"literal _yn";
Point p(0, y);
return p;
}
Point operator "" _z(const char* l)
{
float z = atof(l);
std::cout<<"literal _zn";
Point p(0, 0, z);
return p;
}
int main(int argc, char **argv)
{
Point& p = 12_x + 2_x + 3_y + 4_z;
p.print();
}
执行后,我得到以下输出:
literal _z
Constructor
literal _y
Constructor
literal _x
Constructor
literal _x
Constructor
Returning ref: operator+
Returning ref: operator+
Returning ref: operator+
Destructor
Destructor
Destructor
Destructor
(14, 3, 4)
当我将行更改为Point& p = 12_x;
时,会发出一个错误,说明您无法从右值初始化引用。
当我将其更改为const Point& p = 12_x;
时,我得到:
literal _x
Constructor
(12, 0, 0)
Destructor
我预计会出现这两种情况中的任何一种,而不是第一种,所以我的问题是:第一种情况到底会发生什么?
附言:我使用的是带有gcc 4.8.1的MinGW。编译字符串:g++ --std=c++11 -Wall main.cpp -o out.exe
您的+运算符签名不正常,它应该返回一个新的临时签名,而不是对LHS的引用。您实际上已经实现了+=。
这就是您的加号运算符将绑定到非常量引用的原因。
虽然不能将临时引用绑定到非常数引用,但可以对其执行非常数操作。因此,当第一个术语实际上是临时的时,它将编译您的+运算符。
即使swap()
是一个非常数函数,它也可以使用vector<int>().swap( myVec )
从myVec
中清除内存。
当您希望在一行中创建字符串构建函数,并且在对象下面使用成员ostringstream
上的operator<<
时,它也可以用于字符串构建函数。这是安全的,因为在这种情况下,您进行的最后一个调用是str()
调用,它返回的值不是成员引用。
在您的情况下,您也可以在operator+
的实现中使用此构造
class Point
{
public:
Point & operator+=( const Point& ); // as you implemented +
Point operator+( const Point & rhs ) const
{
return Point( *this ) += rhs;
}
};
在行中:
Point& p = 12_x + 2_x + 3_y + 4_yz;
您得到一个对临时对象的引用,该对象在执行该行后立即被销毁,从而导致未定义的行为。实际上,您可以在日志中看到:调用四个构造函数,然后调用四个析构函数——因此,在调用print()
之前,所有创建的对象都会被销毁。
当你写:
const Point& p = 12_x;
根据12.2/5 ([class.temporary])
,它会导致12_x
返回的临时的生存期延长,因此只有当引用超出范围时,也就是说,这次是在调用print()
之后,才会调用析构函数。
PS:摘录自12.2/4
和12.2/5
:
有两种情况下,临时性在不同于完整表达结束时被破坏。(…)第二个上下文是引用绑定到临时的。(…)[示例:
struct S {
S();
S(int);
friend S operator+(const S&, const S&);
~S();
};
S obj1;
const S& cr = S(16)+S(23);
S obj2;
(…)绑定到引用
cr
的临时T3
在cr
的生命周期结束时,即在程序结束时被销毁。(…)
顺便说一句,这里的例子也提供了实现operator+
的正确方法(除了你可能甚至不需要它是friend
)。您在代码中所写的内容应该是operator+=
。
表达式12_x
创建了一个临时对象,创建对临时对象的引用显然是不起作用的,当临时对象被破坏时会引用什么(一旦它所在的表达式完成,它就会是什么)?
但是,只要引用变量在作用域内,进行const
引用就会导致编译器延长临时对象的生存期。
带有加法的较长表达式也会创建临时对象,但由于operator+
函数被定义为返回引用,因此整个表达式的结果就是引用。不幸的是,它将是对临时对象的引用,使用它将导致未定义的行为,所以你很幸运它能工作。
正如Potatoswatter所指出的,一个重新值引用应该与临时对象一起使用。这是C++11中引入的一种新的引用,用双安培数表示,如
Point&& p = 12_x;
- 创建引用向量的优雅方式
- 为什么当我们有常量引用时创建临时对象?
- 在函数内创建的对象的范围 - 如果在函数外部存储和访问引用,它们是否有效?
- 如何从绝对地址的 C 样式指针创建对C++对象的引用
- 如何创建对smart_pointer的引用?
- CMake 引用我在 ~/bin 中创建的随机 shell 脚本(即使我删除了它)?
- C++在函数中创建的对 Eigen::Matrix 的悬空引用
- 如何在C++中使用 new 运算符创建对动态创建的数组的引用?
- 从引用创建指向基类的智能指针
- 通过向构造函数其他对象引用页面来创建对象
- C++为具有引用成员变量的类创建复制构造函数
- 创建<int>对整数数组指针的矢量引用 (C++)
- 哪个 const 与哪个引用将更改参数并创建一个 const 对象?
- 将非左值作为常量引用参数传递.临时是在本地作用域还是在调用方作用域中创建的?
- 为什么从引用创建共享指针会复制对象?
- 您可以使用BOOST_AUTO创建引用类型吗?
- c++在函数内部创建引用变量
- 从多个临时文件中创建引用
- 在两个语句中创建引用变量
- 创建引用和创建对象的主要区别是什么?