c++在同一个函数中返回字符串引用和传递字符串引用

C++ returning a string reference and passing a string reference in the same function

本文关键字:字符串 引用 返回 同一个 函数 c++      更新时间:2023-10-16

我一直在和上级讨论这个功能:

const std::string &GetCurrentDataSourceName(std::string & sName)
{
   sName = GetAnotherComponent().GetName();
   return  sName;
}

函数返回类型和形参类型都包含在其中是否有任何原因?该函数的目的是返回1个值。

他的动机和用例是可以这样做的:

std::string sName = "";
SetSomeValue(GetCurrentDataSourceName(sName));

我认为最好像这样省略参数:

const std::string &GetCurrentDataSourceName()
{
   return  GetAnotherComponent().GetName();
}

但是他让我怀疑我的编码能力。

编辑:返回的值必须是const。代码也进行了更新,以显示返回值的来源。

原来的函数看起来很难看。它肯定会从任何阅读代码的人那里调用"WTF",因此应该避免这样做。

请注意,您的替换依赖于somevalue是全局对象或类似对象。如果不是这样(例如,如果somevalue是在函数内部计算的),您将返回一个悬空的引用错误代码。

我想说最干净的方法是摆脱单行代码,依靠移动语义和/或[N]RVO来完成他们的工作,只是按值返回:

std::string GetCurrentDataSourceName()
{
   return somevalue;
}

似乎这个函数的全部意义就是获取一些字符串值,在这种情况下,我将这样写:

std::string GetCurrentDataSourceName() {
  return somevalue;
}

除非您有很好的理由返回constsomevalue的引用,否则只需按值返回。如果在函数中计算somevalue,而您刚刚省略了,那么绝对不要返回引用。

我看不出有输出参数的好理由。你上司的例子可以这样写:

std::string sName = GetCurrentDataSourceName();
SetSomeValue(sName);

您建议的代码…

const std::string &GetCurrentDataSourceName()
{
   return  somevalue;
}

…是令人担忧的,因为它返回一个变量的引用,这意味着你必须有一些深刻的见解和保证,关于somevalue的生命周期和潜在的进一步更改/失效如何与潜在的客户端使用相关。

那很好,如果你碰巧返回一个引用说static const std::string存储一个"组件"名称(如你编辑的问题所暗示的),但它的通常不是你想要的东西,因为经常通过引用返回是偶然的,引用是一个(称为-)函数局部变量,它超出了函数返回的范围,因此,任何看到上述返回类型的人都会立即对该函数感到紧张,并且至少想要仔细检查实现或确保文档给出相关保证。

一般来说,最好写…

std::string GetCurrentDataSourceName() // "const" here if a member function
{
   return ...somevalue..;
}

…如果需要设置一个局部变量,可以这样使用:

SetSomeValue(sName = GetCurrentDataSourceName());

它也更方便,因为调用者不一定需要一个命名的局部变量,如果他们只是想例如将数据源名称传递给另一个函数,在表达式中使用它(例如添加前缀/引号,转义用于URL),或者在某处流。

在这种情况下,表面上没有理由既接受要设置为引用参数的变量,又返回新值。

我不认为"方便在一行中连接函数调用"是这样做的正当理由。

最好按值返回,而不是按const引用返回。特别是当你可以使用c++11时。

std::string GetCurrentDataSourceName(std::string sName)
{
    //do some work with sName..
    return sName;
}

因为你要修改sName,所以你要进行复制,使用move语义,你可以通过函数调用节省复制开销,像这样

sName = GetCurrentDataSourceName(std::move(sName)); //no copy required