【问题标题】:Overloading operator [] for both read and write重载运算符 [] 用于读取和写入
【发布时间】:2011-12-05 22:53:19
【问题描述】:

我在重载运算符 [] 以在对象中读取和写入时遇到问题。这是一个包含不同组件的大型代码,我不会在此处列出所有细节,因为它无济于事。简而言之,我拥有的是以下内容

class MyObject(){
    inline SetterProxy& operator[](int i) {
        SetterProxy a(i);
        return a;
    }
    inline double operator[](int i) const{            
        return some_value;
    }
}

第一个重载的 [] 可以很好地分配值(如果您想知道 SetterProxy 是什么,我必须使用 Proxy 类才能在分配值之前进行一些检查和内部函数调用)。但是,应该在读取时调用的第二个不起作用并且代码崩溃。我不确定这里发生了什么,但是当我注释掉第一个时,它就可以正常工作了!会不会是编译器以某种方式混淆了两者,因为它们都是内联的?

任何想法将不胜感激。

编辑: 好的,这里是 SetterProxy 本身:

class SetterProxy{
private:
    Vec v;
    int i;
    double *ptr_val;
public:
    inline SetterProxy(Vec v_, int i_) {
        v = v_;
        i = i_;
        VecGetArray(v,&ptr_val);
    }
    inline ~SetterProxy(){
        VecRestoreArray(v,&ptr_val);
    }

    inline void operator=(double rhs ){
        ptr_val[i] = rhs;
    }
};

虽然我不认为它直接来自那个。同样最初我让它按值返回,尽管将它更改为引用会更有效。我认为这应该是安全的,因为分配是在 Proxy operator=() 类中完成的,之后代理类超出了范围。无论哪种方式,这都不能解决我的问题!

【问题讨论】:

  • 这可能与您在SetterProxy 中所做的事情有关吗?您能否用它的作用摘要更新问题?
  • const 对象或非const 对象崩溃时,您是在调用operator[] 吗?
  • @seth:尝试了 const 和 non-const。调用 printf("%f\n",a[0]); 之类的代码时,代码会崩溃。同样使用 cout 我得到了操作符

标签: c++ operator-overloading


【解决方案1】:

您正在返回对局部变量的引用 - 当运算符返回时它超出范围,使您的引用悬空。如果您将警告设置提高到合理的水平,一个好的编译器应该会警告您。

【讨论】:

  • 问题:例如在 printf 语句中读取值时,代码不应该调用第二个运算符吗?
  • @GradGuy :不,调用哪个重载取决于对象的常量性,而不是您尝试对返回值执行的操作。如果您的对象不是 const,则将始终调用第一个重载。
  • 好吧。无论如何要求编译器调用第二个函数用于只读目的?
  • @GradGuy :给它一个唯一的名称,或者在调用期间使您的对象为 const 。但无论如何我都看不到重点,因为如果第一个重载写得正确,那么即使出于只读目的调用它也没有什么坏处。
  • @ildjarn:问题是第一个使用代理来设置值,因此它返回的内容具有代理类的类型,因此 printf 抱怨它!我想我必须写一个新的 printf 或重载
【解决方案2】:

正如@Stuart Golodetz 的回答中所指出的,您正在返回对SetterProxy 的引用,该引用引用了a,这是您的方法本地的,因此在返回时超出了范围。

您应该改为返回一个SetterProxy 实例按值:这应该没什么大不了的,SetterProxy 可能只保存索引和对“父”对象的引用,所以编译器为它生成的拷贝构造函数会很好,拷贝也不会很昂贵。

顺便说一句,除非您想允许负索引,否则通常的习惯用法是使用size_t 作为数组中的索引。

【讨论】:

  • @SethCarnegie: unsigned int 不能保证足够大以容纳可以分配的任何对象的大小(以及它们内部的索引);想想 Windows x86_64:unsigned int 是 32 位,而 size_t 是 64 位(所以 unsigned int 不能用作 >4GB 数组的索引 - 它可以存在于那里,而 size_t 可以)。查看here 的其他示例。
  • @SethCarnegie:使用ptrdiff_t,因为它已签名(避免麻烦)并且足够大。使用size_t,如果您正在为某些老式 DSP 编程,或者如果您愿意接受各种错误和一般麻烦,以便看起来符合公众舆论,和/或为了看起来符合标准库的约定(支持现在不存在的古老系统)。不用说“看起来符合”的理由在技术上是不合理的。但有时牺牲技术会更好,尤其是对于一个原始的经理。
  • @SethCarnegie:既然你在问,你可能认为你已经知道答案了,如果是真的,这意味着这个问题并不完全诚实,并且旨在欺骗。 :-( 但无论如何,范围问题是 16 位系统上的一个问题。因此 C 标准要求 ptrdiff_t 至少为 17 位。现在我敢打赌你不知道 。正如他们所说,一点知识是危险的。
  • @AlfP.Steinbach 不,这是一个真正的问题,我不是想欺骗你,很抱歉你这么认为。所以根据你的回答,我认为我的问题的答案是肯定的,对吧?我无法从您的回复中真正看出,因为它似乎在谈论 16 位系统。
  • @Seth:对不起。我误解了一个巧合。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-19
  • 2016-04-27
  • 2012-05-10
  • 1970-01-01
  • 2017-09-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多