我知道"文字"(c字符串,int或其他)存储在某处(在一个只读数据部分显然是.rodata)也许这不准确......
我想了解为什么此代码导致运行时错误:
#include <iostream>
using namespace std;
const int& foo()
{
return 2;
}
const char* bar()
{
return "Hello !";
}
int main() {
cout << foo() << endl; // crash
cout << bar() << endl; // OK
return 0;
}
Run Code Online (Sandbox Code Playgroud)
foo返回一个文字的const引用(2)为什么会导致崩溃?是存储在foo()堆栈中的整数2?
(注意原来的问题标题有“而不是右值”而不是“而不是常量引用”。下面的答案之一是对旧标题的回应。为了清楚起见,这是固定的)
C 和 C++ 中的一种常见构造是用于链式赋值,例如
int j, k;
j = k = 1;
Run Code Online (Sandbox Code Playgroud)
第二=首先进行,用该表达k=1具有副作用k被设置为1,而表达式本身的值是1。
但是,在 C++ 中合法(但在 C 中不合法)的一种构造如下,它对所有基本类型都有效:
int j, k=2;
(j=k) = 1;
Run Code Online (Sandbox Code Playgroud)
在这里,表达式j=k具有设置j为 2的副作用,并且表达式本身成为对 的引用j,然后将其设置j为 1。据我所知,这是因为表达式j=k返回非- const int&,例如一般来说是左值。
通常也建议将此约定用于用户定义的类型,如Meyers Effective C++中的“Item 10: Have assignment operators return a (non-const) reference to *this”中所述。本书的这一部分并没有试图解释为什么参考文献是非引用的const,甚至没有注意到const顺便提及的非引用性。
当然,这当然增加了功能,但(j=k) = 1;至少可以说这种说法似乎很尴尬。
如果约定改为使用内置赋值返回const引用,那么自定义类也将使用此约定,并且 C 中允许的原始链式构造仍然有效,无需任何无关的副本或移动。例如,以下正确运行:
#include …Run Code Online (Sandbox Code Playgroud) 我在这里阅读了SO问题并理解了答案的这一部分:“但是如果你将一个临时值绑定到一个非常量引用,你可以继续“永远”传递它,只是为了让你对对象的操作消失,因为在某个地方一路上你完全忘记了这只是暂时的。”
也就是说,在以下内容中:
#include <iostream>
void modifyValue(int& rValue) {
rValue++;
}
int main() {
modifyValue(9899);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果右值可以绑定到非常量左值引用,那么可能会进行许多修改,这些修改最终会被丢弃(因为右值是临时的),这是无用的。
然而,这似乎定义良好(写入临时值就像写入任何值一样,生命周期与写入的有效性无关)。
这是禁止指定绑定的完全正确的理由(即使绑定将被明确定义),但是一旦我认为禁止这种绑定会强制需要转发引用,我的问题就开始形成。
是否还有其他原因(即,除了写入临时值之外)为什么右值无法绑定到非常量左值引用?
我在代码中遇到了一个错误,该错误正在调用错误的重载函数。
问题归结为:
void func(const int* const& ptr){
std::cout << "LValue reference\n";
}
void func(const int* const&& ptr){
std::cout << "RValue reference\n";
}
int main(){
const int* ptr;
func(ptr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码按预期工作,它打印LValue reference。但是,当我改变const int* ptr到int* ptr,该程序打印RValue reference。这对我来说很奇怪,因为我通过了一个确认的LValue。这使我相信正在发生某种隐式转换,从而将其转换为RValue。我确实使用godbolt编译器资源管理器进行了研究,乍看之下它会证实我的怀疑,但是我对汇编一无所知,因此无法确定。
所以问题是:这里发生了什么?
在学习 C++ 时,我决定编写一个简单的模板化二叉搜索树 (bst) 并遇到以下问题:我希望能够通过传递左值和右值来构造一个 bst 。同样,我希望能够插入左值和右值。所以我最终得到了很多我不喜欢的重复代码:const T &valT &&val
/// copy constructor
explicit inline constexpr binary_search_tree(const T &val)
: _root{std::make_unique<binary_search_tree_node>(val)} {}
/// move constructor
explicit inline constexpr binary_search_tree(T &&val)
: _root{std::make_unique<binary_search_tree_node>(std::move(val))} {}
Run Code Online (Sandbox Code Playgroud)
对于构造函数, wherebinary_search_tree_node是其私有成员binary_search_tree,然后还必须提供复制和移动构造函数:
struct binary_search_tree_node {
T value;
std::unique_ptr<binary_search_tree_node> left;
std::unique_ptr<binary_search_tree_node> right;
// prohibit creation of tree_node without value
inline constexpr binary_search_tree_node() = delete;
/// copy constructor
explicit inline constexpr binary_search_tree_node(const T &val)
: value{val}, left{nullptr}, right{nullptr} {} …Run Code Online (Sandbox Code Playgroud) 我的理解是这ConcreteType&&是一个右值并且TemplateType&&是“完美转发”。
我正在尝试使用完美转发,但 clang-tidy 将其解释为右值引用。
clang 和 gcc 不会抱怨,但在进行任何进一步分析之前,clang-tidy 将其标记为解析错误,所以我不确定这是代码问题还是 clang-tidy 问题。
我怀疑这与我在构造函数中使用它有关,但我不确定。
最低代码:
#include <memory>
template <typename T>
class my_wrapper {
T val;
public:
my_wrapper(T&& val_)
: val{std::forward<T>(val_)} {}
};
struct my_struct {
int x;
};
auto xyz() {
my_struct ms{3};
return my_wrapper<my_struct>(ms);
}
Run Code Online (Sandbox Code Playgroud)
错误信息:
Error while processing /path/foo.cpp.
/path/foo.cpp:20:25: error: no matching constructor for initialization of 'my_wrapper<my_struct>' [clang-diagnostic-error]
my_wrapper<my_struct> wrap(ms);
^
/path/foo.cpp:5:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from …Run Code Online (Sandbox Code Playgroud) 我使用C++ https://cppinsights.io/查看实例化的进度,Function&&和Function之间有一些令人困惑的地方。
我评论了cppinsights生成的代码。
template<typename Function>
void bind(int type, Function&& func)
{
}
/*
// instantiated from the function above:
template<>
inline void bind<void (*)()>(int type, void (*&&)() func)
{
}
*/
template<typename Function>
void bindtwo(int type, Function func)
{
}
/*
template<>
inline void bindtwo<void (*)()>(int type, void (*func)())
{
}
*/
void test()
{
std::cout << "test" << std::endl;
}
int main()
{
bind(1, &test);
bindtwo(2, test);
}
Run Code Online (Sandbox Code Playgroud) 根据C++标准2003:
An lvalue (3.10) of a non-function, non-array type T can be converted to an rvalue.
Run Code Online (Sandbox Code Playgroud)
数组和函数不能转换为rvalue是什么意思?
在C++ 11中,通常的做法是通过引用将左值传递给函数.
int& f(int& a){
return a;
}
int main(void){
auto a = 1;
auto b = f(a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是,是否可以通过右值引用将值传递给函数并通过lvalue返回此值?
int& f(int&& a){
return a;
}
int main(void){
auto b = f(1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它为什么或为什么不可能?
我创建了一个包含整数数组的类Array.从main函数,我正在尝试使用[]获取Array中的数组元素,就像在main中声明的数组一样.我重载了运算符[],如下面的代码所示; 第一个函数返回一个左值,第二个函数返回一个右值(未显示构造函数和其他成员函数.)
#include <iostream>
using namespace std;
class Array {
public:
int& operator[] (const int index)
{
return a[index];
}
int operator[] (const int index) const
{
return a[index];
}
private:
int* a;
}
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试从main调用这两个函数时,即使变量未用作左值,也只访问第一个函数.如果可以通过使用左值函数来处理所有事情,我无法看到为rvalue创建单独函数的重点.
以下代码是我使用的主要功能(Operator <<适当重载.):
#include "array.h"
#include <iostream>
using namespace std;
int main() {
Array array;
array[3] = 5; // lvalue function called
cout << array[3] << endl; // lvalue function called
array[4] = array[3] // lvalue function called for both
}
Run Code Online (Sandbox Code Playgroud)
有什么方法可以调用右值函数吗?是否还需要为左值和右值定义函数?