2010-07-19 133 views
12

我有一些关于C++的基本问题。考虑下面的代码,我试图返回一个字符串。另一个C++学习时刻:从函数返回字符串

const std::string& 
NumberHolder::getValueString() { 
    char valueCharArray[100]; 
    sprintf_s(valueCharArray,"%f",_value); 
    std::string valueString(valueCharArray); 
    return valueString; 
} 

我试图返回一个字符串的值为一个名为_value的类成员。不过,我得到了一个警告,我试图传回一个指向局部变量的指针。这当然是一件坏事。如果我现在已经足够了解C++,这意味着当有人尝试使用它时,我传回的指针已经具有调用它的删除。所以我修改:

const std::string& 
NumberHolder::getValueString() { 
    char valueCharArray[100]; 
    sprintf_s(valueCharArray,"%f",_value); 
    std::string valueString = new std::string(valueCharArray); 
    return (*valueString); 
} 

这应该在堆栈上创建一个指针,它将在该函数之外生存。这里有两个问题:1)它无法编译,我不明白为什么(error = 无法从'std :: string *'转换为'std :: basic_string < _Elem,_Traits,_Ax>')和2)这似乎是一个潜在的内存泄漏,因为我要依靠别人来调用这个人的删除。我应该在这里使用什么样的模式?

+2

这不是关于返回一个字符串;这是关于返回一个参考。一个悬而未决的参考。 – 2010-07-19 15:51:25

+0

除了你的参考问题..为什么const反正呢? – 2010-07-19 15:54:03

+0

std :: string valueString = new std :: string(valueCharArray); return(* valueString); 您忘记了valueString指针,这就是为什么不编译: std :: string * valueString = new std :: string(valueCharArray); – Fanatic23 2010-07-19 15:56:44

回答

22

你通过在堆中分配它击败有std::string的地步!

仅仅通过值这样的回报是:

std::string NumberHolder::getValueString() 
{ 
    char valueCharArray[100]; 
    sprintf_s(valueCharArray,"%f",_value); 
    return std::string(valueCharArray); 
} 

几乎每一个编译器现在会做return value optimization (RVO)在return语句,所以没有副本应作出。考虑以下几点:

NumberHolder holder; 
// ... 
std::string returnedString = holder.getValueString(); 

随着RVO,编译器将生成的代码用于上述实施NumberHolder::getValueString()使得std::string是在returnedString位置构造,因此不需要拷贝。

+0

好的...这是我可以学习的东西。这里发生了什么事?我认为我在函数范围内创建了一个匿名命名的字符串,然后通过将值传递回来,我有效地创建了它的副本,它位于调用此函数之上的范围内。那是对的吗?更新:好的,我现在明白了。 – JnBrymn 2010-07-19 15:49:29

+2

是的,你正在创建一个匿名的'std :: string',但是编译器实际上会为这个特定的情况进行优化,并且会通过直接在返回值的位置上构造'std :: string'来消除副本。 – 2010-07-19 15:51:48

+0

有些人认为你应该返回'const std :: string'。 – Philipp 2010-07-30 16:13:27

15

您会收到此警告,因为您将参考返回给本地字符串,而不是本地字符串的副本。一旦函数返回,本地字符串将被销毁,并且返回的引用无效。因此,你需要按值不参照返回字符串,:

std::string NumberHolder::getValueString() 
+0

存在内存泄漏的问题吗?调用函数将不得不承担删除字符串的责任,对吧?这看起来不是最好的。 – JnBrymn 2010-07-19 15:46:37

+0

'std :: string'负责为你服务。 – 2010-07-19 15:47:26

+5

@John:不要在堆上创建'std :: string'。只需返回本地字符串_by value_。你的第一个例子很好,只是改变返回类型。 – 2010-07-19 15:47:34

0
std::string *valueString = new std::string(valueCharArray); 

你需要创建一个指针变量从new保存结果,因为它返回的指针。然而,理想的解决办法真的只是要返回的值:

std::string NumberHolder::getValueString() { 
    ... 
    return std::string(valueCharArray); 
} 
3

你的第一个尝试是正确的,如果你返回一个临时变量,但在常引用绑定。

const std::string NumberHolder::getValueString(){} 

const std::string& val = NumberHolder::getValueString(); 

const。但你的第二次尝试是危险的,取决于别人删除。