在埃克尔,第1卷,第:367
//: C08:ConstReturnValues.cpp
// Constant return by value
// Result cannot be used as an lvalue
class X {
int i;
public:
X(int ii = 0);
void modify();
};
X::X(int ii) { i = ii; }
void X::modify() { i++; }
X f5() {
return X();
}
const X f6() {
return X();
}
void f7(X& x) { // Pass by non-const reference
x.modify();
}
int main() {
f5() = X(1); // OK -- non-const return value
f5().modify(); // OK
// Causes compile-time errors:
//! f7(f5());
//! f6() = X(1);
//! f6().modify();
//! f7(f6());
} ///:~
为什么f5() = X(1)
赢得成功? 这里发生了什么???
Q1。 当他X(1)
-这到底是怎么回事呢? 这是一个构造函数调用-不应该在该再读取X::X(1);
它是类的实例-是不是类的实例是这样的: X a(1);
编译器如何确定哪些X(1)
是? 我的意思..名装修发生这样.. X(1)
构造函数调用会转化为类似: globalScope_X_int
作为函数名.. ???
Q2。 当然临时对象用于存储所产生的对象X(1)
创建,然后我就不会被那个然后分配给对象f5()
返回(这也将是一个暂时的对象)? 鉴于f5()
返回将很快被丢弃的临时对象,他怎么可以指定一个恒定的临时到另一个不变临时??? 有人能解释清楚为什么: f7(f5());
应该以恒定的临时和不普通的旧reult f5();
你所有的问题归结为C ++中的规则,它说,一个临时对象(一个没有名字)不能绑定到非const引用。 (因为斯特劳斯认为这可能会引发逻辑错误......)
一个难点,就是你可以在临时调用的方法:使X(1).modify()
是不错,但f7(X(1))
不是。
至于创建临时在那里,这是编译器的工作。 语言精确的是,临时应只能存活直到当前满表达(不再)的端部,其是用于类,它们的析构函数临时实例重要的规则具有副作用。
因此,以下语句X(1).modify();
可以完全翻译成:
{
X __0(1);
__0.modify();
} // automatic cleanup of __0
考虑到这一点,我们可以攻击f5() = X(1);
。 这里我们有两种临时工,和转让。 分配的两个参数都必须充分评估的分配被调用之前,但为了不准确。 一个可能的翻译是:
{
X __0(f5());
X __1(1);
__0.operator=(__1);
}
( 另一翻译交换,其中顺序__0
和__1
被初始化 )
和键,它的工作是__0.operator=(__1)
是一个方法调用,并且方法可以在临时对象被调用:)
我并不完全答案满意,所以我在拍了一下:
“更有效的C ++”,斯科特迈尔斯。 第19项:“明白了临时对象的起源”
。 关于“临时变量”,好了,我怀疑与基督教劳直接指出,这是完全错误的布鲁斯Eckel的报道! 哎呀! 他是(Eckel的)把我们当做实验品! (这将是一本好书,对于像我这样的新手,一旦他改正自己的错误,所有)
迈尔:“在C ++中是看不见的真实临时对象 - 它们不会出现在源代码中的出现只要创建一个非堆对象,但没有点名这些无名的对象通常在两种情况之一发生:当隐式类型转换。应用进行函数调用成功,当函数返回的对象。”
“首先考虑在其中创建临时对象进行函数调用成功的情况下,出现这种情况时,传递给函数的对象的类型是不一样的参数,以它被绑定的类型。”
“这些转换传递对象时由值或传递给一个参考给const参数时才会发生。传递对象到参考到非const参数时,它们也不会发生”。
“在其下创建临时对象的第二组的情况是,当一个函数返回一个对象”。
“任何时候你看到一个参考给const参数,所述可能性是存在的一个临时将创建绑定到参数。每当你看到函数返回一个对象,一个临时将被创建(和后来破坏)”。
答案的另一部分中找到:“迈尔:有效的C ++”,在“导言”:
“复制构造是用来与相同类型的不同的对象初始化对象:”
String s1; // call default constructor
String s2(s1); // call copy constructor
String s3 = s2; // call copy constructor
“也许拷贝构造函数的最重要的用途是定义什么意思传递和返回值的对象。”
关于我的问题:
f5() = X(1) //what is happening?
这里一个新的对象没有被初始化,故我这不是初始化(拷贝构造函数):这是一个任务(如马修中号指出)。
所述的临时创建因为按照迈耶(顶部段),这两个函数返回值,正在被创建,以便临时对象。 如马修指出使用伪代码,就变成: __0.operator=(__1)
和一个逐位复制发生(由编译器完成)。
关于:
void f7(X& x);
f7(f5);
ERGO,暂时无法创建(迈尔:上面的段落)。 若是已经宣布: void f7(const X& x);
然后暂时将已经建立。
关于临时对象是一个常数:
迈耶说它(马修):“暂时将创建绑定到该参数。”
所以暂时只能被绑定到一个恒定的参考,它本身不是一个“常量”对象。
关于:什么是X(1)
迈耶Item27,有效C ++ - 3E,他说:
“C-风格转换是这样的:(T)表达式//投表达为类型Ť
函数式的管型使用以下语法:T(表达)//投表达是类型T的”
因此, X(1)
是一个函数样式转换。 1
表达被转换为类型X
。
梅耶又说它:
“关于我唯一一次使用老式的铸铁是,当我想打电话给一个明确的构造一个对象传递给一个函数,例如:
class Widget {
public:
explicit Widget(int size);
...
};
void doSomeWork(const Widget& w);
doSomeWork(Widget(15)); //create Widget from int
//with function-style cast
doSomeWork(static_cast<Widget>(15));
不知怎么的,故意的对象创建没有“感觉”像一个演员,所以我可能会使用函数式的,而不是铸的static_cast在这种情况下。”
下面是当你执行你的代码到底发生了什么的例子。 我做了一些修改,以澄清幕后的过程:
#include <iostream>
struct Object
{
Object( int x = 0 ) {std::cout << this << ": " << __PRETTY_FUNCTION__ << std::endl;}
~Object() {std::cout << this << ": " << __PRETTY_FUNCTION__ << std::endl;}
Object( const Object& rhs ){std::cout << this << ": " << __PRETTY_FUNCTION__ << " rhs = " << &rhs << std::endl;}
Object& operator=( const Object& rhs )
{
std::cout << this << ": " << __PRETTY_FUNCTION__ << " rhs = " << &rhs << std::endl;
return *this;
}
static Object getObject()
{
return Object();
}
};
void TestTemporary()
{
// Output on my machine
//0x22fe0e: Object::Object(int) -> The Object from the right side of = is created Object();
//0x22fdbf: Object::Object(int) -> In getObject method the Temporary Unnamed object is created
//0x22fe0f: Object::Object(const Object&) rhs = 0x22fdbf -> Temporary is copy-constructed from the previous line object
//0x22fdbf: Object::~Object() -> Temporary Unnamed is no longer needed and it is destroyed
//0x22fe0f: Object& Object::operator=(const Object&) rhs = 0x22fe0e -> assignment operator of the returned object from getObject is called to assigne the right object
//0x22fe0f: Object::~Object() - The return object from getObject is destroyed
//0x22fe0e: Object::~Object() -> The Object from the right side of = is destroyed Object();
Object::getObject() = Object();
}
你要知道,在大多数现代编译器的拷贝构造将被避免。 这是因为由编译器它是由优化(返回值优化)。 在我的输出我已经显式删除优化展现什么是真正按照标准发生。 如果要去除这项优化过使用下面的选项:
-fno-elide-constructors
文章来源: Temporary objects - when are they created, how do you recognise them in code?