返回右值或左值

Posted

技术标签:

【中文标题】返回右值或左值【英文标题】:returning either a rvalue or an lvalue 【发布时间】:2019-02-23 08:09:56 【问题描述】:

如果s[0] 从未被分配,我想定义s[i] 以返回0,如果s[i] 早先被分配(以实现稀疏数组),则返回对s[i] 的引用。以下代码可以做到这一点,但由于 map 的语义,每当我尝试获取其值时,它最终都会创建 s[i]

struct svec
  map<int,double> vals;
  /*                                                                                                
  double operator[](int index)                                                                     
    return (vals.count(index) > 0) ? vals[index] : 0                                                        ;                                                                           
    else return 0;                                                                                  
                                                                                                   
  */
  double &operator[](int index)
    return vals[index];
  
;

int main()
svec s;
s[0] = 10;
cout << s[1] << endl;

我希望注释代码用于解析表达式s[1]。但是,如果我取消注释它,我会收到错误消息。

【问题讨论】:

关于您的注释代码,地图中的条目数等于某个最大索引。请记住,您的地图可能具有例如的值密钥09。这将使地图的大小等于2,但最大“索引”为9。您还应该使重载按值const 返回,如double operator[](int index) const;。最后,如果您只能有非负数(即正数和零),请使用 unsigned 而不是 int 至于你的问题,你需要考虑一下给出一个无效的“索引”是什么意思。它应该返回默认值吗?它应该抛出异常吗?您是否应该将地图作为基础数据类型?为什么不是向量(似乎更适合这个)? 我希望返回默认值 0。 一个函数只能有一个返回类型。您不能同时返回左值和右值 您不能让函数根据其参数值返回不同的类型。重新思考您的设计。 【参考方案1】:

您不能重载返回值,因此您必须坚持按引用或按值(或按指针等)返回。通过引用返回的问题是您必须引用存在于内存中的现有值。当然,当值在地图中时,这很好。如果不是,您必须创建默认值并将其存储在内存中。然后你必须确保正确删除它以不泄漏内存,还要确保用户没有持有对值的引用,因为它会引入意外行为。

此外,您必须考虑用户可以更改您返回的值这一事实。如果您返回相同的默认值,则用户可以将其更改为另一个值。然后所有后续调用将返回对新值的引用。每次返回时将默认值重置为 0 对于仍然保留对它的引用的所有用户来说也是意料之外的。

您可能可以以稳定的方式解决此问题,但可能需要大量样板代码。在这种情况下,我建议将负担放在用户身上。

class SparseVector 
private:
    std::unordered_map<int, double> elements;

public:
    void set(int index, double value) 
        elements[index] = value;
    

    double& get(int index, double& optional) 
        auto it = elements.find(index);
        if (it != elements.end())
            return it->second;
        else
            return optional;
    

    double& get(int index) 
        auto it = elements.find(index);
        if (it != elements.end())
            return it->second;
        throw std::runtime_error(
            "Couldn't find element at index " + std::to_string(index) + 
            "! Use get(int index, double& optional) if you don't want errors."
        );
    


int main() 
    double default_value = 0.0;
    SparseVector vector;

    std::cout << vector.get(0, default_value) << std::endl;

【讨论】:

以上是关于返回右值或左值的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中将右值引用转换为临时参数到 const 左值返回的正确方法

C++11 左值右值右值引用详解

c++:函数左值或右值

从函数返回的左值引用实际上是右值吗(从调用者的角度来看)?

为啥这个函数在给定右值参数的情况下返回一个左值引用?

C语言 啥叫做左值?右值?