在
template <typename T>
T const & foo(T const & dflt)
{ return /* ... */ ? /* ... */ : dflt; }
int x = foo(5);
Run Code Online (Sandbox Code Playgroud)
在分配给x之前,对临时的引用是否"存活"?
(我知道它在foo()调用的持续时间内存活,但是赋值让我犹豫)
有问题的代码在这里依赖于const引用有一些合法用途,即我需要两个独立的函数
T const & foo_cr(T const & dflt);
T const & foo_v(T dflt);
Run Code Online (Sandbox Code Playgroud)
我想避免(只是依赖于同名的不同签名对我来说似乎有点危险.)
我听说临时对象只能分配给常量引用.
但是这段代码给出了错误
#include <iostream.h>
template<class t>
t const& check(){
return t(); //return a temporary object
}
int main(int argc, char** argv){
const int &resCheck = check<int>(); /* fine */
typedef int& ref;
const ref error = check<int>(); / *error */
return 0;
}
Run Code Online (Sandbox Code Playgroud)
得到的错误是 invalid initialization of reference of type 'int&' from expression of type 'const int'
考虑以下功能:
void f(const char* str);
Run Code Online (Sandbox Code Playgroud)
假设我想使用stringstream生成一个字符串并将其传递给此函数.如果我想在一个声明中这样做,我可能会尝试:
f((std::ostringstream() << "Value: " << 5).str().c_str()); // error
Run Code Online (Sandbox Code Playgroud)
这给出了一个错误:'str()'不是'basic_ostream'的成员.好的,所以operator <<返回ostream而不是ostringstream - 如何将它转换回ostringstream?
1)这个演员安全吗?
f(static_cast<std::ostringstream&>(std::ostringstream() << "Value: " << 5).str().c_str()); // incorrect output
Run Code Online (Sandbox Code Playgroud)
现在有了这个,结果是运算符<<("Value:")调用,它实际上调用了ostream的运算符<<(void*)并打印了一个十六进制地址.这是错的,我想要的是文字.
2)为什么operator << on临时std :: ostringstream()会调用ostream运算符?当然临时有一种'ostringstream'而不是'ostream'?
我可以施放临时强制执行正确的操作员!
f(static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << "Value: " << 5).str().c_str());
Run Code Online (Sandbox Code Playgroud)
这似乎有效并将"Value:5"传递给f().
3)我现在依赖于未定义的行为吗?演员看起来很不寻常.
我知道最好的选择是这样的:
std::ostringstream ss;
ss << "Value: " << 5;
f(ss.str().c_str());
Run Code Online (Sandbox Code Playgroud)
...但我对在一行中做这件事的行为很感兴趣.假设有人想制作一个(可疑的)宏:
#define make_temporary_cstr(x) (static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << x).str().c_str())
// ...
f(make_temporary_cstr("Value: " << 5));
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绑定
我知道下面写的代码是非法的
void doSomething(std::string *s){}
int main()
{
doSomething(&std::string("Hello World"));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
原因是我们不允许获取临时对象的地址.但我的问题是为什么?
让我们考虑以下代码
class empty{};
int main()
{
empty x = empty(); //most compilers would elide the temporary
return 0;
}
Run Code Online (Sandbox Code Playgroud)
公认的答案在这里提到
"通常编译器会将临时和副本构造为两个对象,它们位于内存的完全相同的位置,并避免复制."
根据声明,可以得出结论,临时存在于某个内存位置(因此可能已经采用了它),编译器决定通过在临时存在的同一位置创建就地对象来消除临时对象. .
这是否与临时地址不能采取的事实相矛盾?
我还想知道如何实现返回值优化.有人可以提供与RVO实施相关的链接或文章吗?
允许这样做的背后的设计理由是什么?
const Foo& a = function_returning_Foo_by_value();
Run Code Online (Sandbox Code Playgroud)
但不是这个
Foo& a = function_returning_Foo_by_value();
Run Code Online (Sandbox Code Playgroud)
?
第二行可能出现什么问题(第一行不会出错)?
考虑一下:
std::string foo();
void bar() {
const std::string& r1 = foo();
static const std::string& r2 = foo();
}
Run Code Online (Sandbox Code Playgroud)
我知道第一次调用产生的字符串的生命周期foo()将延长到生命周期r1.
r2然而,暂时的约束呢?它会一直存在到示波器的末端,还是在bar()重新进入时仍然存在?
注意:我对特定编译器是否这样做感兴趣.(我对我们使用的那个很感兴趣,我可以轻松地测试它.)我想知道标准对此有何看法.
在下面的代码中,pS并s.pS保证在最终的线相等?换句话说,在声明中S s = S();,我可以确定S不会构建临时的吗?
#include <iostream>
using namespace std;
struct S
{
S() { pS = this; }
S* pS;
};
int main()
{
S s = S();
S* pS = &s;
cout << pS << " " << s.pS << endl;
}
Run Code Online (Sandbox Code Playgroud)
在每个编译器中我都测试了这个pS == s.pS,但是我对标准不够熟悉,以至于能够确保这是有保证的.
众所周知,在大多数情况下,T&&意味着"这是一个临时对象".但是,如果想要从函数返回临时对象,他/她可以按如下方式声明函数:
template<class T>
T f()
{
T t;
......
return t;
}
Run Code Online (Sandbox Code Playgroud)
或(注意:不正确)
template<class T>
T&& f()
{
T t;
......
return t;
}
Run Code Online (Sandbox Code Playgroud)
但我认为后者是过度的,因为前者足够向后兼容.
然而,我也发现它std::forward()的返回类型被声明为T &&,所以我确信我对此的理解是不完整的.
我真正的问题是:我们何时何地将函数的返回类型声明为T &&?
以下代码给出了悬空指针错误。
std::vector<std::pair<std::string, int>> c;
for (auto& b : c) {
const auto& [s, i] = b;
std::string_view v = s.substr(i);
std::cout << v;
}
Run Code Online (Sandbox Code Playgroud)
我认为它b保存了对 的引用std::pair<std::string, int>,所以s应该是对pair对象中字符串的引用。为什么这会产生悬空指针错误?我在这里缺少什么?godbolt 链接: https: //godbolt.org/z/4zMvbr
c++ ×10
temporary ×10
reference ×3
c++11 ×2
const ×2
rvalue ×2
c++17 ×1
constructor ×1
lvalue ×1
return-type ×1
stdstring ×1
string ×1
string-view ×1
stringstream ×1
templates ×1