让我们来看看这两个功能:
std::string get_string()
{
std::string ret_value;
// Calculate ret_value ...
return ret_value;
}
void process_c_string(const char* s)
{
std::cout << s << endl;
}
Run Code Online (Sandbox Code Playgroud)
这里有两个可能的process_c_string带有参数的调用get_string.
没有绑定const引用的返回对象get_string.
process_c_string(get_string().c_str());
Run Code Online (Sandbox Code Playgroud)用绑定const引用返回的对象get_string.
const std::string& tmp_str = get_string();
process_c_string(tmp_str.c_str());
Run Code Online (Sandbox Code Playgroud)我知道第二种方式是有效的,但第一种方式是什么,标准对此案例有什么看法呢?返回的临时对象是否get_string会在process_c_str完成之前删除,因为没有const reference它?
注意:这两个版本在MSVC中都可以.
通过一个例子更好地解释:
tok.h
#include <string>
static const char* defaultDelim = ".,;";
class Tokenizer {
public:
Tokenizer():
// 'delim' is the const ref member that is initialized by the temp string
delim( (altDelim.size())? altDelim : std::string(defaultDelim) )
{}
size_t scan(const std::string& str)
{ return str.find_first_of(delim); }
static void setDelim(const std::string& d) { altDelim = d; }
private:
static std::string altDelim;
const std::string& delim;
};
Run Code Online (Sandbox Code Playgroud)
main.cpp中
#include <iostream>
using namespace std;
#include "tok.h"
std::string Tokenizer::altDelim;
int main()
{
Tokenizer tok;
size_t pos = …Run Code Online (Sandbox Code Playgroud) 当我有下面的伪类:
template <class T> class tmplClass
{
void doSomething(T input);
};
Run Code Online (Sandbox Code Playgroud)
有一种方法来改变void doSomething(T input)到void doSomething(const T& input)时的sizeof(T)是在较大的系统架构.
tmplClass<char> c;例如,void doSomething(T input)当您有tmplClass<[another big class with lots of variables]>使用时,意味着使用void doSomething(const T& input)
C++标准允许将const引用绑定到rvalues,从而延长临时的生命周期,直到引用超出范围.但是,我无法弄清楚这是如何实际编译的,让我用一个例子来解释:
std::string foo() {
return std::string("foo");
}
void bar() {
VeryBigObject obj;
// Perhaps do something with the big object
}
int main(int, char **) {
const std::string &foo_str = foo();
bar();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
据我所知,使用x86架构作为例子,首先foo()调用函数并在堆栈中构造字符串对象,这意味着从rsp寄存器中减去所需的空间量(假设为64)位结构); 之后,rsp寄存器返回其原始值,释放函数foo()正在填充的堆栈空间,如果我理解正确,调用bar()将使用该堆栈空间来构造VeryBigObject,这将覆盖该字符串.
考虑到所有这些,在调用foo()汇编域后,如何延长字符串的生命周期?
为什么对字符串参数的const引用可以采用字符串文字?像字符串文字"hello"不是变量,为什么这段代码有效?
class CVector {
public:
int x, y;
CVector() {};
~CVector() { delete ptr; }
string* ptr;
void doSomething(const string& str) { ptr = new string(str); }
void print() { cout << "\n" << *ptr; }
};
int main()
{
result.doSomething("asdas");
result.print();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
首先,我认为引用作为参数用于避免复制过程并直接访问作为参数的变量(尽管我仍然可以正确).但字符串文字"asdas"不是变量,为什么参数将字符串文字作为参数?我的意思是因为参数str是一个引用,它将成为该实体的别名,对吧?如果是这样,文字是否只是变量?
参数列表不应该由string& strconst引用而不是const引用组成,因此文本将用于构造str?
并且只要引用是活着的,并不是const引用使引用的实体保持活动状态?如果是这样,你为什么要这样做呢?
考虑以下代码 -
#include <iostream>
#include <stdio.h>
const int & retRef() {
return 6;
}
int main()
{
const int& k = retRef();
printf("Value: %d\n", k);
printf("Address: %p\n", &k);
printf("Value: %d\n", k);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是 -
Value: 6
Address: 0x7ffd45bf544c
Value: 32692
Run Code Online (Sandbox Code Playgroud)
为什么在打印变量的地址后值发生了变化k?如果我更换线const int& k = retRef()用const int& k = 6;的输出为预期.
为什么这种行为不同?提前致谢
我的印象是,它的std::initializer_list行为可能类似于 C++ 中的文字字符串,甚至进一步,它们可能会延长 const 引用的生命周期。这是正确的评估吗?
initializer_list稍后可以在本地范围内以某种方式引用an 中的对象(无需复制它们)吗?在全球范围内?
例如,这个测试在 GCC 和 clang 中通过。这只是偶然吗?
#include<cassert>
#include<initializer_list>
struct A{
double const* p;
A(std::initializer_list<double> il){ p = &*(il.begin() + 1); };
};
double f(){return 5.;}
int main(){
A a1{1.,2.,3.};
assert( *a1.p == 2. );
A a2{1., f(), f()};
assert( *a2.p == 5. );
}
Run Code Online (Sandbox Code Playgroud) 这可能已经被问到了。
为什么允许向非常量变量分配对常量的引用?
为什么这是允许的
int mut {0};
const int & r_to_c {mut};
mut = 1;
// now r_to_c changed to 1!
// But it was supposed to be a reference to something constant!
Run Code Online (Sandbox Code Playgroud)
?
当然,我不能改变引用到常量本身的值。我不能
r_to_c = 2;
Run Code Online (Sandbox Code Playgroud)
但是是不是const执行的资格太少了?我希望,从 const-ness 的承诺来看,不允许绑定到可变变量。
否则const给我什么保证?它们看起来很弱,而且这似乎很容易诱使程序员用脚射击自己。
我知道 C++ 以允许人们用脚射击自己而闻名。允许危险的事情发生我没有问题。在这种情况下,我的问题是,在这种情况下,它似乎是故意欺骗,因为const这里的语义不是人们所期望的。
我的问题是关于编译器和语言语义的问题,而不是特别关于引用的问题(我可以使用分配给非常量变量地址的常量指针来问同样的问题。像int mut{0}; const int * p_to_c{&mut};)。
为什么引用常量(或常量指针)的语义只是“你不能使用这个特定的窗口来修改你看到的东西(但如果你有其他非常量的窗口,你可以修改它)”而不是更强大的“这只能是声明为常量并且编译器保证它保持不变的东西的窗口”?
[术语说明:我使用表达式“const 引用”而不是“const 引用”,因为“const 引用”被解释为T& const- 与调用T* const“const 指针”一致 - 不存在。]
const TBigType& a = [](){
TBigType result;
// ...
return result;
}();
use(a); // by const ref
Run Code Online (Sandbox Code Playgroud)
可以像这样在 const ref 中捕获结果吗?
考虑我们需要实现一个f带有模板参数的函数T t。该函数不应同时复制t和接受rvalues和lvalues,因此可能有两种实现:
template <class T>
void f(const T& t) { ... }
template <class T>
void f(T&& t) { ... }
Run Code Online (Sandbox Code Playgroud)
如果我们想改变t里面f的值或者需要保留类的值,就得使用第二个版本了。那么根据这个思路,我们何时以及为什么会选择第一个选项?