C++ 返回常量引用的参数时出现问题

C++ 返回常量引用的参数时出现问题,c++,pass-by-reference,C++,Pass By Reference,我知道为什么下面的方法不正确,所以我不是在问为什么。但我感到很遗憾的是,在我看来,这是一个非常大的编程障碍 #include <iostream> #include <string> using namespace std; string ss("hello"); const string& fun(const string& s) { return s; } int main(){ const string&

我知道为什么下面的方法不正确,所以我不是在问为什么。但我感到很遗憾的是,在我看来,这是一个非常大的编程障碍

#include <iostream>
#include <string>
using namespace std;

string ss("hello");

const string& fun(const string& s) {
        return s;
}

int main(){
        const string& s = fun("hello");
        cout<<s<<endl;
        cout<<fun("hello")<<endl;
}
#包括
#包括
使用名称空间std;
字符串ss(“你好”);
常量字符串和乐趣(常量字符串和s){
返回s;
}
int main(){
const string&s=fun(“你好”);

cout该技术是有效的,并且一直在使用。但是,在第一个示例中,您正在将
const char*
转换为临时
std::string
,并尝试返回它,这与将const引用返回存储在其他位置的对象不同。在第二个示例中,您正在执行相同的操作,但您正在执行在销毁临时文件之前使用结果,在本例中,这是合法的,但很危险(请参见第一个案例)


更新:请允许我澄清一下我的答案。我是说问题在于创建临时对象,而不是正确处理所创建对象的生命周期。该技术是一种很好的技术,但它(以及许多其他好技术)要求满足函数的前置和后置条件。部分负担落在函数程序员(应该记录它)身上,部分负担也落在客户端身上。

是的,我同意在某些情况下这是一个相关问题

我会使用一个引用计数指针来“解决”它

难道不可能想象这样一种情况:方法实现者想要返回一个常量引用的参数,而这个参数是不可避免的吗

问错了,真的。你所要做的就是包括返回的引用是否可能是一个参数(通过引用传递),以及作为接口的一部分记录该参数(这通常也是显而易见的)让调用方决定要做什么,包括将临时对象转换为显式对象,然后传递该对象

通常需要记录返回指针和引用的生命周期,例如std::string::data的生命周期

在这种情况下C++会做什么?< /P>


通常,您可以通过值来传递和返回这通常是通过std::copy(在本例中用于目标迭代器)来完成的。

我感觉到了您的痛苦。我发现在其他情况下,返回const引用似乎是正确的,但也有其他一些不好的问题


幸运的是,在C++ C++中解决了这个微妙的问题。总是按值返回。新的移动构造函数会使事情按照你的意愿快速地进行。

< P>在即将到来的C++标准中,R值引用可以用来保持你的临时对象“存活”,并修正你所拥有的问题。


您可能还需要查找完美转发和移动构造函数。

我认为您在C++98中自找麻烦:)

这可以通过两种方式解决。首先,您可以使用共享指针。在这种情况下,内存将由
shared\u ptr
自动管理,您就完成了!但是,在大多数情况下,这是一个糟糕的解决方案。因为您确实没有在多个引用之间共享内存。
auto\u ptr
是此pro的真正解决方案BLeM,如果您一直考虑使用堆。<代码> AutoPPTR <代码>需要一个小的<强> > <强>改进,而C++ 98中没有真正可用的改进,即:移动语义! 更好的解决方案是,通过使用r值引用,允许所有权在引用之间移动,这在C++0x中是存在的


在C++中,建立对象的生命周期是很重要的。一种常用的技术是为每个对象确定一个“所有者”。所有者负责确保对象存在的时间长,并且在不需要时删除它。 通常,所有者是在实例变量中保存所属对象的另一个对象。处理此问题的其他典型方法是使其成为全局、类的静态成员、局部变量或使用引用计数指针


在您的示例中,字符串对象没有明确的所有权。它不属于主体()函数,因为它不是局部变量,并且没有其他所有者。

< P>我认为这是C++的一个小缺点。
  • 函数的返回值只有在其参数为时才有效
  • 隐式转换意味着函数的参数不是它看起来的对象
我不同情那些不考虑他们有指针/引用的对象的生命周期的人。但是隐式转换,这当然是一种语言特性,有微妙的优点和缺点,使这里的分析变得不容易。有时隐式转换是坏消息,这就是为什么
explicit
关键字存在的原因。Bu问题不在于转换为
string
通常是不好的,它只是对这个函数不好,以这种不正确的方式使用

函数的作者可以通过定义重载来禁用隐式转换:

const char *fun(const char *s) { return s; }
这一变化本身就意味着以前不好的代码可以工作。因此我认为在这种情况下这样做是一个好主意。当然,如果有人定义了一个类型,而该类型的
fun
的作者从未听说过,并且有一个
操作符std::string()
。此外,
fun
不是一个实际的函数,对于更有用的例程,您可能不想提供一个在
char*
上运行的等价函数。在这种情况下,
void fun(const char*);
至少会强制调用方显式转换为字符串,这可能有助于他们正确使用函数

或者,打电话的人可能会注意到他提供了一个
char*
,并返回了一个
字符串的引用。在我看来,这是一个免费的
const char *fun(const char *s) { return s; }