我最近关注了C++ 0x的glvalues,xvalues和prvalues以及rvalue引用的概念.然而,有一件事仍然让我失望:
什么是"函数类型的右值引用"?在草稿中多次提到它.为什么要引入这样的概念?有什么用途?
我正在用C++ 11编写一个小程序,并且第一次真正使用异常.
我有一个关于如何有效地捕获异常的问题,经过一些谷歌搜索我仍然没有答案.
这是一个问题:通过(const?)左值引用或(const?)右值引用捕获异常之间的效率(或推荐)是什么?
在代码中,这给:
1)
try { throw std::exception{"what"}; }
catch (std::exception& ex) {}
Run Code Online (Sandbox Code Playgroud)
2)
try { throw std::exception{"what"}; }
catch (const std::exception& ex) {}
Run Code Online (Sandbox Code Playgroud)
3)
try { throw std::exception{"what"}; }
catch (std::exception&& ex) {}
Run Code Online (Sandbox Code Playgroud)
4)
try { throw std::exception{"what"}; }
catch (const std::exception&& ex) {}
Run Code Online (Sandbox Code Playgroud) 我正在努力理解rvalue参考文献.我看到他们是如何在构造函数中使用,之类的东西std::move和std::forward,但我还是不明白为什么这不起作用:
void func(string&& str)
{
cout << str << endl;
}
int main(int argc, char* argv[])
{
string s("string");
func(s);
}
Run Code Online (Sandbox Code Playgroud)
这样做:
template<typename T>
void func(T&& str)
{
cout << str << endl;
}
int main(int argc, char* argv[])
{
string s("string");
func(s);
}
Run Code Online (Sandbox Code Playgroud)
为什么它与函数模板版本一起使用?
(我在comp.std.c ++上询问了这个问题的变体,但没有得到答案.)
为什么f(arg)在这段代码中的调用调用const ref重载f?
void f(const std::string &); //less efficient
void f(std::string &&); //more efficient
void g(const char * arg)
{
f(arg);
}
Run Code Online (Sandbox Code Playgroud)
我的直觉说f(string &&)应该选择重载,因为arg无论如何都需要转换为临时值,并且临时匹配rvalue引用比lvalue引用更好.
这不是GCC和 MSVC中发生的事情(编辑:谢谢Sumant:它不会发生在GCC 4.3-4.5中).至少在G ++和 MSVC中,任何左值都不会绑定到右值引用参数,即使创建了一个中间临时值.实际上,如果不存在const ref重载,编译器会诊断出错误.然而,编写f(arg + 0) 或f(std::string(arg)) 不选择右值引用过载如你所愿.
从我对C++ 0x标准的阅读中,似乎在考虑是否f(string &&)可行时应考虑将const char*隐式转换为字符串,就像传递const lvalue ref参数时一样.第13.3节(重载解析)在很多地方没有区分rvalue refs和const引用.此外,似乎阻止左值绑定到右值引用(13.3.3.1.4/3)的规则不适用,如果存在中间临时值 - 毕竟,从临时值移动是完全安全的.
这是:
编辑:我有一个相关的后续问题:C++ 0x rvalue引用 - lvalues-rvalue绑定
我有一个简单的课程:
class X
{
std::string S;
X (const std::string& s) : S(s) { }
};
Run Code Online (Sandbox Code Playgroud)
我最近读过一些关于rvalues的内容,我一直在想,如果我应该编写X使用rvalue的构造函数,那么我能够检测出std::string类型的临时对象吗?
我认为应该看起来像:
X (std::string&& s) : S(s) { }
Run Code Online (Sandbox Code Playgroud)
据我所知,在支持C++ 11的编译器中实现std :: string应该在可用时使用它的移动构造函数.
考虑:
#include <cstdlib>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
class Gizmo
{
public:
Gizmo() : foo_(shared_ptr<string>(new string("bar"))) {};
Gizmo(Gizmo&& rhs); // Implemented Below
private:
shared_ptr<string> foo_;
};
/*
// doesn't use std::move
Gizmo::Gizmo(Gizmo&& rhs)
: foo_(rhs.foo_)
{
}
*/
// Does use std::move
Gizmo::Gizmo(Gizmo&& rhs)
: foo_(std::move(rhs.foo_))
{
}
int main()
{
typedef vector<Gizmo> Gizmos;
Gizmos gizmos;
generate_n(back_inserter(gizmos), 10000, []() -> Gizmo
{
Gizmo ret;
return ret;
});
random_shuffle(gizmos.begin(), gizmos.end());
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,有两个版本Gizmo::Gizmo(Gizmo&&) …
假设我有一个(普通的)类,它是可移动构造和可移动分配但不可复制构造或可复制分配:
class movable
{
public:
explicit movable(int) {}
movable(movable&&) {}
movable& operator=(movable&&) { return *this; }
movable(const movable&) = delete;
movable& operator=(const movable&) = delete;
};
Run Code Online (Sandbox Code Playgroud)
这很好用:
movable m1(movable(17));
Run Code Online (Sandbox Code Playgroud)
当然,这不起作用,因为m1它不是右值:
movable m2(m1);
Run Code Online (Sandbox Code Playgroud)
但是,我可以包m1中std::move,它投射到一个右值引用,以使其工作:
movable m2(std::move(m1));
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.现在,假设我有一个(同样微不足道的)容器类,它包含一个值:
template <typename T>
class container
{
public:
explicit container(T&& value) : value_(value) {}
private:
T value_;
};
Run Code Online (Sandbox Code Playgroud)
但是,这不起作用:
container<movable> c(movable(17));
Run Code Online (Sandbox Code Playgroud)
编译器(我试过clang 4.0和g ++ 4.7.2)抱怨我正在尝试movable在container初始化列表中使用已删除的复制构造函数.同样,包裹value在std::move使得它的工作:
explicit container(T&& value) : value_(std::move(value)) {} …Run Code Online (Sandbox Code Playgroud) 对于类类型,可以分配实际上不允许内置类型的临时对象.此外,默认生成的赋值运算符甚至会产生左值:
int() = int(); // illegal: "expression is not assignable"
struct B {};
B& b = B() = B(); // compiles OK: yields an lvalue! ... but is wrong! (see below)
Run Code Online (Sandbox Code Playgroud)
对于最后一个语句,赋值运算符的结果实际上用于初始化非const引用,该引用将在语句之后立即变为陈旧:引用未直接绑定到临时对象(它不能作为临时对象只能是绑定到一个const或右值引用)但绑定到其生命周期未延长的赋值结果.
另一个问题是从赋值运算符返回的左值看起来不像它可以被移动,尽管它实际上是指临时的.如果有任何东西使用赋值的结果来获取值,它将被复制而不是移动,尽管移动是完全可行的.此时值得注意的是,问题是根据赋值运算符描述的,因为此运算符通常可用于值类型并返回左值引用.任何返回对象引用的函数都存在同样的问题,即*this.
一个潜在的解决方法是重载赋值运算符(或返回对象引用的其他函数)以考虑对象的类型,例如:
class G {
public:
// other members
G& operator=(G) & { /*...*/ return *this; }
G operator=(G) && { /*...*/ return std::move(*this); }
};
Run Code Online (Sandbox Code Playgroud)
C++ 11提供了如上所述重载赋值运算符的可能性,并且可以防止上面提到的细微对象失效并同时允许将赋值结果移动到临时值.这两个运营商的实施可能完全相同.虽然实现可能相当简单(基本上只是swap()两个对象中的一个),但它仍然意味着提出问题的额外工作:
返回对象的引用的函数(例如,赋值运算符)是否应该观察被赋值对象的右值?
另外一个(在评论中由Simple提到)是不重载赋值运算符,但是使用a &来限制它的使用到lvalues:
class GG {
public:
// other …Run Code Online (Sandbox Code Playgroud) 是否有任何情况下const&&在range-for循环中使用它是否有意义?
for (const auto && x : c) // ?
Run Code Online (Sandbox Code Playgroud) 背景和以前的搜索
我正在寻找一种优雅的方法来在C++ 14中使用基于范围的for循环对容器(例如std :: vector)进行反向迭代.寻找一个解决方案,我发现这个Q/A.它基本上告诉我,这不是标准库的一部分,我必须自己使用boost或实现一个适配器.我不想使用boost,所以我现在正在寻找最好的实现.
除了前面提到的Q/A中提出的建议外,我还发现了这个实现以及关于这个主题的博客.大多数实现非常相似,看起来相当不错.然而,它们都有一个陷阱:正如在这个注释中所指出的,如果你用一个临时对象调用反向适配器,你可能会得到一个悬空引用:
for (const auto& v : reverse_iterate(getContainer()))
Run Code Online (Sandbox Code Playgroud)
关于基于范围的for循环中的临时对象的问题,这个答案确实帮助了我的理解.但是,我们可以做些什么来防止悬空参考呢?
我的解决方案
基于这个背景,我正在寻找一种能够摆脱这种陷阱的实现.在下面的实现中,我使用额外的rvalue-reference rx_来延长输入参数的生命周期iff reverse_iterate是用rvalue引用调用的.
编辑:不要使用此解决方案.如公认的解决方案所指出的那样是错误的.
template <typename T>
class reverse_range
{
T &&rx_; // rvalue-reference to prolong livetime of temporary object
T &x_; // reference to container
public:
explicit reverse_range(T &x) : rx_(T{}), x_(x) {}
explicit reverse_range(T &&rx) : rx_(std::move(rx)), x_(rx_) {}
auto begin() const -> decltype(this->x_.rbegin())
{
return x_.rbegin();
}
auto end() …Run Code Online (Sandbox Code Playgroud) rvalue-reference ×10
c++ ×9
c++11 ×9
for-loop ×2
c++14 ×1
const ×1
constructor ×1
exception ×1
shared-ptr ×1
string ×1
templates ×1
temporary ×1
try-catch ×1