" Effective C++ "第3项说"尽可能使用const",它给出了一个例子:
const Rational operator*(const Rational& lhs,
const Rational& rhs);
Run Code Online (Sandbox Code Playgroud)
防止客户端犯下这样的暴行:
Rational a, b, c;
...
(a * b) = c; // invoke operator= on the result of a*b!
Run Code Online (Sandbox Code Playgroud)
但是,函数的非参考返回值是否已经是一个rvalue?那么为什么还要这么做呢?
#include <iostream>
using namespace std;
template<typename T>
void f(T&&) { cout << "f(T&&)" << endl; }
template<typename T>
void f(const T&&) { cout << "f(const T&&)" << endl; }
struct A {};
const A g1() { return {}; }
const int g2() { return {}; }
int main()
{
f(g1()); // outputs "f(const T&&)" as expected.
f(g2()); // outputs "f(T&&)" not as expected.
}
Run Code Online (Sandbox Code Playgroud)
问题描述嵌入在代码中.我的编译器是clang 5.0.
我只是好奇:
在这种情况下,为什么C++会以不同方式处理内置类型和自定义类型?
我是C++的新手.我读过的这本书告诉我,如果+为某个类对象(比如类)重载了plus()运算符,那么string这个问题会更加具体.
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1("abc");
string s2("def");
string s3("def");
cout<<(s1+s2=s3)<<endl;
int x=1;
int y=2
int z=3;
cout<<(x+y=z)<<endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
正如您所料,第一个cout陈述是正确的,而第二个陈述是错误的.编译器投诉x+y不是可修改的左值.我的问题是为什么+操作符为string对象返回可修改的左值但不是为了int?
对于类类型,可以分配实际上不允许内置类型的临时对象.此外,默认生成的赋值运算符甚至会产生左值:
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) 显然,不允许在ref-qualifiers上重载 - 如果删除&或者&&(只是标记,而不是它们的函数),这段代码将无法编译:
#include <iostream>
struct S {
void f() & { std::cout << "Lvalue" << std::endl; }
void f() && { std::cout << "Rvalue" << std::endl; }
};
int main()
{
S s;
s.f(); // prints "Lvalue"
S().f(); // prints "Rvalue"
}
Run Code Online (Sandbox Code Playgroud)
换句话说,如果您有两个具有相同名称和类型的函数,则必须定义两者,如果您定义其中任何一个.我认为这是故意的,但是原因是什么?例如,为什么不允许调用&&rvalues 的版本(如果已定义),以及f()以下变体中的其他所有内容的"primary" (反之亦然 - 尽管这会让人感到困惑):
struct S {
void f() { std::cout << "Lvalue" << std::endl; }
void f() && { std::cout << "Rvalue" …Run Code Online (Sandbox Code Playgroud) 我有一个表示布尔值向量的C数据结构; 由于我无法控制的原因,bools'在内部存储为具有两个神奇值(不是0和1 ......)的整数,表示真和假.我创建了一个包装这个C结构的C++类,它运行得很好.我已经实现了set()和get()方法:
void Class::set(size_t index , bool value) {
if (value)
c_ptr[index] = SPECIAL_TRUE_VALUE;
else
c_ptr[index] = SPECIAL_FALSE_VALUE;
}
Run Code Online (Sandbox Code Playgroud)
这没关系; 但理想情况下我想重载operator [],但是我不清楚如何/如果我能做到这一点 - 由于bool和整数值之间的特殊转换?
#include <vector>
using namespace std;
struct TempData {
vector<int> data;
TempData() {
for(int i = 0; i < 100; i++) data.push_back(i);
}
// vector<int> GetData() { // function 1
// return move(data);
// }
vector<int>&& GetData() { // function 2
return move(data);
}
};
int main() {
vector<int> v;
{
TempData td;
v = td.GetData();
}
}
Run Code Online (Sandbox Code Playgroud)
function 1和 和有function 2什么区别?
将function 1构造一个 temp vector,move(data)然后将 temp 分配vector给v?
没有更多细节可以添加...