从将其作为参数的函数返回引用
Return a reference from a function that takes it as a parameter
从概念上讲,我有一个类可以做到这一点。请注意,基础数据类型在实际应用程序中更为复杂。这只是为了简化:
class A
{
private:
std::map<std::string, int> database;
public:
bool knowsValue(std::string string_id); // Returns true if string_id is in database
const int& getValueA(std::string string_id); // Returns reference to int mapped to string_id in database
}
由于为未知string_id
调用 getValueA 会导致错误,因此这两个命令通常一起调用:
if obj.knowsValue(string_id)
int val = obj.getValueA(string_id)
else
std::cout << "Value does not exist in database";
因为这需要对数据库对象进行两次后续find
操作,所以我将这个函数设为bool getValueB(std::string string_id, int& val)
,如果string_id
在数据库中,则返回 true,并将映射的值分配给val
。
两个getValue
函数的内容几乎相同,所以我想在getValueA
中重用getValueB
。这就是我无法深度的地方,通过这次尝试:
const int& getValueA2(std::string string_id)
{
static int val_tmp; // If not static, this object is deleted after the function call and the reference becomes invalid
if (getValueB(string_id, val_tmp))
return static_cast<const int&>(val_tmp);
else
return static_cast<const int&>(0);
}
显然,static
关键字在这里是不合适的,因为值不应该在函数之间共享。此外,引用未const
getValueB
的事实也是次优的。
我的问题:
- 编写
getValueA2
的正确方法是什么,它试图返回它在参数中获得的引用?中间val_tmp
似乎令人讨厌。 - 是否可以在此结构中
const
引用?
我倾向于将getValueB
改为const int& getValueB(std::string string_id, const bool value_exists_in_db)
来解开这个烂摊子,但我有兴趣找出什么是可能的以及我哪里出错了。
编辑:请注意,理想情况下,const int& getValueA(std::string string_id)
声明不应更改,以避免代码库其余部分的更改。
我认为,从根本上说,你不应该试图将这两者结合起来,因为它们实际上在做完全不同的事情。
一个参数版本(const int& getValueA(const std::string&)
)返回对某处某个值的引用。
双参数版本(bool getValueA2(const std::string&, int&)
)将值的副本分配给调用方提供的新位置。
这里有几个选项:
- 将实现分开。
- 稍微将两个参数版本更改为类似于
bool getValueA2(const std::string &, const int *&)
的内容,以巩固功能。这是非常丑陋的,而且基本上没有吸引力。 - 按照别人说的去做,并更改签名。
- 重构这两种方法,以使用实际包含通用功能的第三个辅助方法。
如果你选择#4,它可能看起来像这样(请注意,我不能做一个更相关的例子,因为你没有给我足够的细节来这样做):
auto getValueAImpl(const std::string &key) const {
return database.find(key);
}
const int &getValueA(const std::string &key) {
auto it = getValueAImpl(key);
if (it != database.end()) return it->second;
throw std::runtime_error("key not found");
}
bool getValueA(const std::string &key, int &val) {
auto it = getValueAImpl(key);
if (it == database.end()) return false;
val = it->second;
return true;
}
通过常量引用返回int
是一种悲观。int
复制起来很便宜;与引用基础的指针便宜或便宜。 出于这个原因,我会说正确的做法是将getValueA
更改为按值返回,然后您可以按照getValueB
的方式实现它:
int getValueA(const std::string& string_id)
{
int val_tmp;
if (getValueB(string_id, val_tmp))
return val_tmp;
else
return 0;
}
另一种选择是将两者结合起来,并返回一个std::optional<int>
:
std::optional<int> getValue(const std::string& string_id)
{
auto it = database.find(string_id);
if (it == database.end()) {
return std::nullopt;
} else {
return *it;
}
}
注意:我还将参数类型更改为const std::string&
。 复制字符串可能很昂贵,因此在这种情况下使用引用是有意义的。
如果你可以选择使用 C++17,我建议使用std::optional<int>
作为返回类型。
std::optional<int> getValueA2(std::string string_id)
{
auto iter = database.find(id);
// If found, return the value.
if ( iter != database.end() )
{
return {iter->second}; // Equivalent to std::optional<int>{iter->second};
}
else
{
// Not found. Return a default constructed object
return {};
}
}
如果您不能使用 C++17,您可以使用std::pair<bool, int>
作为返回类型作为穷人的替代品std::optional<int>
。
如果找到该值,则返回{true, iter->second}
。
如果未找到该值,则返回{false, 0}
。
const int* getValuePtr(std::string const& id) const
{
auto it = database.find(id);
if(it==database.end()) return nullptr;
return &(it->second);
}
指针是可能的引用。
在使用点:
if(auto x=foo.getValuePtr("bob")){
// use *x here safely
}
如果您的函数返回引用,则该函数需要保证返回的引用用于调用方使用它时仍然存在的内容。
在您的示例中;
const int& getValueA2(std::string string_id) { static int val_tmp; // If not static, this object is deleted after the function call and the reference becomes invalid if (getValueB(string_id, val_tmp)) return static_cast<const int&>(val_tmp); else return static_cast<const int&>(0); }
那么val_tmp
必须像您一样static
,或者以某种方式分配以便它继续存在。 如果调用方使用返回的引用,则删除static
关键字会导致调用方具有未定义的行为 - 因为就程序而言,当函数返回时val_tmp
将不复存在。
由于您希望函数以某种方式获取值,因此更好的选择是按值返回,而不是引用。
int getValueA2(std::string string_id)
{
int val_tmp;
if (getValueB(string_id, val_tmp))
return val_tmp;
else
return 0;
}
这完全没问题,假设getValueB()
通过引用接受val_tmp
并使用该引用为变量分配一个有效值。
- 从函数返回const char*数组
- 检查函数返回类型是否与STL容器类型值相同
- 从 c 或 cpp 系列子函数返回到主函数
- 从函数返回任意简单类型的数据
- 警告:在函数返回类型 [-Wignore 限定符] 时忽略类型限定符
- 从 C++ 中的函数返回数组地址问题
- VirtDisk.h QueryChangesVirtualDisk() 函数返回 RangeCount 为 0
- 为什么glGetSubroutineIndex为不同的函数返回相同的值?
- 在 c++ 中将函数返回类型指定为模板参数
- 从封装在对象中的函数 C++ 返回时为空的列表
- 为什么向量内部的指针在从函数返回时会发生变化?
- 函数返回的 rvalue 引用(表达式)是 xvalue - 但没有标识?
- 程序中的布尔函数返回输入的范围无论如何都是无效的
- 寿命延长从函数返回引用
- 程序不向函数返回值
- 字符串函数返回奇怪的值
- 类的大问题,以及从空函数c++返回
- 为什么在尝试测量函数返回所需的时间时,我的运行时编号是错误的?
- C++二叉搜索树模板从函数返回节点
- NVCC 错误:string_view.h:constexpr 函数返回是非常量