我正在为linux和windows编写一个应用程序,并注意到GCC构建产生了许多对复制构造函数的无用调用.
以下是产生此行为的示例代码:
struct A
{
A() { std::cout << "default" << std::endl; }
A(A&& rvalue) { std::cout << "move" << std::endl; }
A(const A& lvalue) { std::cout << "copy" << std::endl; }
A& operator =(A a) { std::cout << "assign" << std::endl; return *this; }
};
BOOST_AUTO_TEST_CASE(test_copy_semantics)
{
std::vector<A> vec_a( 3 );
}
Run Code Online (Sandbox Code Playgroud)
此测试仅创建3个元素的向量.我期望3个默认构造函数调用和0个副本,因为没有A左值.
在Visual C++ 2010中,输出为:
default
move
default
move
default
move
Run Code Online (Sandbox Code Playgroud)
在GCC 4.4.0(MinGW)中,( - 02 -std = c ++ 0x),输出为:
default
copy
copy
copy
Run Code Online (Sandbox Code Playgroud)
发生了什么,我该如何解决?副本对于实际类来说是昂贵的,默认构造和移动都很便宜.
在上一个问题之后,我一直在研究ref-qualifiers.
给出下面的代码示例;
#include <iostream>
#include <string>
#include <utility>
struct A {
std::string abc = "abc";
std::string& get() & {
std::cout << "get() &" << std::endl;
return abc;
}
std::string get() && {
std::cout << "get() &&" << std::endl;
return std::move(abc);
}
std::string const& get() const & {
std::cout << "get() const &" << std::endl;
return abc;
}
std::string get() const && {
std::cout << "get() const &&" << std::endl;
return abc;
}
};
int main()
{
A a1;
a1.get();
const …Run Code Online (Sandbox Code Playgroud) 它只是发生在我身上,我注意到std::string的substr操作可能是右值更有效时,它可以盗取分配的内存*this.
N3225的标准库包含以下成员函数声明 std::string
basic_string substr(size_type pos = 0, size_type n = npos) const;
Run Code Online (Sandbox Code Playgroud)
可以实现substr针对rvalues 优化的实现是否会重载并提供两个版本,其中一个版本可以为rvalue字符串重用缓冲区?
basic_string substr(size_type pos = 0) &&;
basic_string substr(size_type pos, size_type n) const;
Run Code Online (Sandbox Code Playgroud)
我想rvalue版本可以实现如下,*this将设置的内存*this重用于移动状态.
basic_string substr(size_type pos = 0) && {
basic_string __r;
__r.__internal_share_buf(pos, __start + pos, __size - pos);
__start = 0; // or whatever the 'empty' state is
return __r;
}
Run Code Online (Sandbox Code Playgroud)
这是否在常见的字符串实现上以有效的方式工作,还是会占用过多的内务管理?
在C++ 11中,值参数(和其他值)在返回时享受隐式移动:
A func(A a) {
return a; // uses A::A(A&&) if it exists
}
Run Code Online (Sandbox Code Playgroud)
至少在MSVC 2010中,右值参考参数需要std::move:
A func(A && a) {
return a; // uses A::A(A const&) even if A::A(A&&) exists
}
Run Code Online (Sandbox Code Playgroud)
我认为内部函数,右值引用和值的行为类似,唯一的区别是在值的情况下,函数本身负责销毁,而对于右值引用,责任在外面.
在标准中对待它们的动机是什么?
在尝试理解右值引用的工作原理时,我最终得到了这段代码:
int* iptr = nullptr;
int*&& irr = iptr;
Run Code Online (Sandbox Code Playgroud)
编译上面的代码会出现以下错误:
错误:对'int*'类型的rvalue引用不能绑定到'int*'类型的左值
我理解这是正确的,但为什么下面的代码,我使用a void*而不是int*编译绑定,编译没有任何问题?运行时行为是正确的还是我应该期望未定义的行为?
int* iptr = nullptr;
void*&& irr = iptr;
Run Code Online (Sandbox Code Playgroud) 在Rvalue References简介中,forward定义如下:
template <typename T>
struct identity { typedef T type; };
template <typename T>
T &&forward(typename identity<T>::type &&a) { return a; }
Run Code Online (Sandbox Code Playgroud)
identity班级的目的是什么?为什么不:
template <typename T>
T &&forward(T &&a) { return a; }
Run Code Online (Sandbox Code Playgroud) 本地左值引用-const和rvalue引用可以延长临时值的生命周期:
const std::string& a = std::string("hello");
std::string&& b = std::string("world");
Run Code Online (Sandbox Code Playgroud)
当初始值设定项不是简单表达式,但使用条件运算符时,这是否也有效?
std::string&& c = condition ? std::string("hello") : std::string("world");
Run Code Online (Sandbox Code Playgroud)
如果其中一个结果是临时对象,但另一个结果不是?
std::string d = "hello";
const std::string& e = condition ? d : std::string("world");
Run Code Online (Sandbox Code Playgroud)
当条件为假时,C++是否要求临时扩展的生命周期?
回答有关不可复制对象的问题时出现了这个问题.
c++ object-lifetime rvalue-reference temporary-objects c++11
我无法通过const引用重载函数来获取值,或者如果它是rvalue则是rvalue引用.问题是我的非const左值绑定到函数的右值版本.我在VC2010中这样做.
#include <iostream>
#include <vector>
using namespace std;
template <class T>
void foo(const T& t)
{cout << "void foo(const T&)" << endl;}
template <class T>
void foo(T&& t)
{cout << "void foo(T&&)" << endl;}
int main()
{
vector<int> x;
foo(x); // void foo(T&&) ?????
foo(vector<int>()); // void foo(T&&)
}
Run Code Online (Sandbox Code Playgroud)
优先级似乎是推导foo(x)为
foo< vector<int> & >(vector<int>& && t)
Run Code Online (Sandbox Code Playgroud)
代替
foo< vector<int> >(const vector<int>& t)
Run Code Online (Sandbox Code Playgroud)
我尝试用r替换rvalue-reference版本
void foo(typename remove_reference<T>::type&& t)
Run Code Online (Sandbox Code Playgroud)
但这只会导致所有内容都解析为const-lvalue引用版本.
我该如何防止这种行为?为什么这仍然是默认值 - 考虑到允许修改rvalue-references似乎很危险,这给我留下了意外修改的局部变量.
编辑:刚添加了非模板版本的函数,它们按预期工作.将函数设为模板会更改重载决策规则吗?那真是令人沮丧!
void bar(const vector<int>& t)
{cout << "void bar(const …Run Code Online (Sandbox Code Playgroud) 想象一下,你有很多重载的方法(在C++ 11之前)看起来像这样:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
};
Run Code Online (Sandbox Code Playgroud)
这个函数复制了a(MyBigType),所以我想通过提供一个版本f来移动a而不是复制它来添加优化.
我的问题是,现在f重载次数将重复:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
void f(MyBigType&& a, int id);
void f(MyBigType&& a, string …Run Code Online (Sandbox Code Playgroud) 我不明白为什么以下代码在GCC 8.0上编译:
decltype(auto) foo(int&& r) {
return r;
}
Run Code Online (Sandbox Code Playgroud)
在foo,声明类型r是int&&,所以返回类型foo也是int&&.但r它本身是一个左值,而左值不能绑定到右值引用.
我错过了什么吗?