我有两个具有以下结构的类:
struct A {
A transform() const;
};
struct B {
// returns a temporary A
A operator*() const;
};
Run Code Online (Sandbox Code Playgroud)
这里的*操作符可能看起来有点奇怪,但考虑到它的使用上下文实际上是很自然的。事实上,它的B存在只是为了为嵌入式语言提供一些语法糖,因此它的方法和运算符旨在为代码提供所需的外观。鉴于B b,获得关联A很快,*b。我有时想A立即调用转换。目前,这需要一些额外的括号(*b).transform()。似乎有一种自然的简化,即b->transform()。但是operator ->应该返回一个指针并且operator *返回一个临时的。我怎样才能实现这样的重载?
我不明白为什么这不起作用:
auto a = (int[]){1, 2, 3, 4, 5};
> error: taking address of temporary array
Run Code Online (Sandbox Code Playgroud)
我知道数组左值在转换为右值时会衰减为指针,但这里数组已经是右值(实际上是纯右值),因此不需要衰减。我本来期望a被推导并初始化为int[5]. 为什么它试图获取临时地址?
什么是基于堆栈的引用?它们与作为对象成员的引用有何不同?标准会讨论这些吗?
我在Herb Sutter 写的一篇文章中看到了这一点:
Q1:下面的代码是合法的C++吗?
// Example 1
string f() { return "abc"; }
void g() {
const string& s = f();
cout << s << endl; // can we still use the "temporary" object?
}
Run Code Online (Sandbox Code Playgroud)
A1:是的。这是一个 C++ 特性……代码是有效的,并且完全符合它的功能。
通常,临时对象仅持续到它出现的完整表达式的结尾。但是,C++ 特意指定将临时对象绑定到堆栈上对 const 的引用将临时对象的生命周期延长到引用本身的生命周期,从而避免了常见的悬空引用错误。在上面的示例中, f() 返回的临时值一直存在到右花括号为止。(请注意,这仅适用于基于堆栈的引用。它不适用于作为对象成员的引用。)
N3290 C++草案,第12.2节,第5点,第10行.
第二个上下文是引用绑定到临时的.绑定引用的临时对象或绑定引用的子对象的完整对象的临时对象在引用的生命周期内持续存在,除了:
在new-initializer(5.3.4)中对引用的临时绑定将持续到包含new-initializer的full-expression完成为止.[例如:
Run Code Online (Sandbox Code Playgroud)struct S { int mi; const std::pair<int,int>& mp; }; S a { 1, {2,3} }; S* p = new S{ 1, {2,3} };// Creates dangling reference- 结束示例] [注意:这可能会引入悬空引用,并鼓励实现在这种情况下发出警告. - 结束说明]
与C++ 03相比,这是一个补充点.但这个例子对我来说是不可理解的.你能用其他任何例子来解释这一点吗?
我知道悬空引用和临时对象是什么,并且std::pair包含两个可能不同数据类型的值.
c++ language-lawyer temporary-objects c++11 dangling-pointer
这个页面说了一件奇怪的事:
仅当您的程序没有将返回值复制到对象并且给定示例时,才会创建临时对象
UDT Func1(); // Declare a function that returns a user-defined type.
...
Func1(); // Call Func1, but discard return value.
// A temporary object is created to store the return
// value
Run Code Online (Sandbox Code Playgroud)
但如果我做了: -
UDT obj=Fuct1;
Run Code Online (Sandbox Code Playgroud)
在我看来,它也将创建一个临时的如下: -
Func()构造一个本地对象.接下来,在调用者的堆栈上复制构造此本地对象,使其temporary object用作obj的复制构造函数的参数.
我错了吗?
这与copy elision有关吗?
此代码无法编译:
class C {};
void foo (C& c) {}
C bar() { return C(); }
int main()
{
foo(bar());
}
Run Code Online (Sandbox Code Playgroud)
编译错误(GCC 4.1.2)符合foo(bar()):
从'C'类型的临时类型初始化'C&'类型的非const引用
当bar()返回一个mutable对象时,它应该编译...
为什么C++不允许上面的代码?
c++ return-value rvalue-reference temporary-objects pass-by-rvalue-reference
随着移动语义的引入,您是否只能将临时工具绑定到const引用更改?非const似乎也延长了寿命.
A getA() { return A();}
A & aref = getA(); //OK
string & str = string("h") + string("i"); //OK again
Run Code Online (Sandbox Code Playgroud)
这是使用msvc,A的析构函数在主退出之前不会被调用.
我在cppreference.com上查找一个临时的生命周期,我发现C++ 14发生了一些变化:
每当引用绑定到临时或临时的基础子对象时,临时的生命周期将扩展为与引用的生命周期匹配,但以下情况除外:
...
绑定到构造函数初始值设定项列表中的引用成员的临时绑定仅在构造函数退出之前持续存在,而不是只要该对象存在.(注意:从DR 1696开始这样的初始化是不正确的)(直到C++ 14)
我检查了标准,真的没有这样的说法.($ 12.2/5临时物品[class.temporary])
这是否意味着从C++ 14开始,临时绑定到引用成员的生命周期将扩展到对象的生命周期?
我尝试了以下代码与GCC和CLANG似乎都没有,临时将被构造函数结束时销毁.
#include <iostream>
struct X {
~X() { std::cout << "X dtor\n"; }
};
struct Y {
Y() : x_(X()) { std::cout << "Y ctor\n"; }
const X& x_;
~Y() { std::cout << "Y dtor\n"; }
};
int main()
{
Y y;
std::cout << "Hello, world!\n";
}
Run Code Online (Sandbox Code Playgroud)
结果:
Y ctor
X dtor
Hello, world!
Y dtor
Run Code Online (Sandbox Code Playgroud)
我误解了吗?
它可以有一个强制执行以下语义的函数参数:
该功能不会更改该参数.调用该函数永远不会为参数创建复制或临时对象.
例:
void f(const std::string & str);
Run Code Online (Sandbox Code Playgroud)
接口告诉客户端参数不会被更改,如果参数已经是std :: string类型,则不会创建副本.
但它仍然可以称之为
const char * hello = "hello";
f(hello);
Run Code Online (Sandbox Code Playgroud)
在输入函数f之前创建一个临时的std :: string对象,并在退出f后再次销毁它.
是否可以通过不同的函数声明或(假设)改变std :: string实现来禁止它.
"15.6.2初始化基础和成员"(N4713)部分在第11项之后有以下示例:
struct A {
A() = default; // OK
A(int v) : v(v) { } // OK
const int& v = 42; // OK
};
A a1; // error: ill-formed binding of temporary to reference
A a2(1); // OK, unfortunately
Run Code Online (Sandbox Code Playgroud)
关于这个例子最后一行的构造有什么不幸?
我在整个参考文献中搜索了其他可能发生的"不幸"行为,但我找不到.
如果在这种特殊情况下不幸,那么它是否可能被视为非法?
c++ ×10
reference ×4
arrays ×1
c++11 ×1
c++14 ×1
const ×1
constants ×1
constructor ×1
return-value ×1
rvalue ×1