如何在函数声明中使用const

时间:2014-07-06 20:00:24

标签: c++ opencv reference const

在opencv中,我碰巧修改了一个传递给我的函数的变量:

void someFunction(const cv::Mat matrix)
{
  double value = 5.0;
  matrix /= value;
}

不仅可以编译,而且在调用someFunction(matrix)后矩阵仍会被修改,即使我没有通过matrix作为参考。我对此代码进行编译的解释是,我实际上并没有更改matrixsomeFunction的任何成员,而是data的指针matrix指向的地址内容,但我不太确定。 由于我有点困惑,我试图在一个小程序中重现这种情况:

#include <iostream>
using namespace std;

class Foo;
{ 
 private:
  int* ptr;

public:
  Foo()
  {
    ptr = new int[1];
    ptr[0] = 1;
  }

  const Foo& operator += ( const Foo& obj) const
  {
    this->ptr[0] += obj.ptr[0];
    return *this;
  }

};

void changeConst(const Foo var)
{
  Foo foo;
  var += foo;
}

int main() 
{
  Foo obj;
  changeConst(obj);
  return 0;
}

事实证明,该程序会编译并有效地更改ptr[0]的{​​{1}}。我发现如果我以这种方式声明运算符obj

+=

它无法编译。为什么是这样?这一发现在我身上产生了许多问题。有没有办法防止函数中指针内容的改变?返回常量引用(Foo& operator += ( const Foo& obj) )的函数的含义是什么?声明函数const Foo&时应该注意什么?简而言之,我应该如何在函数声明中使用const

3 个答案:

答案 0 :(得分:5)

从签名中删除const会导致编译错误,因为您无法从const实例调用非const成员函数。

const版本编译并且似乎违反直觉的原因是您正在修改Mat指向的对象(假设您的意思是/=)或{{ 1}} object,但你没有修改数据成员本身,即指针。

设计表现出这种行为的类型是否有意义是另一回事。就个人而言,我会说允许通过Foo修改const cv::Mat违反了principle of least astonishmentoperator /=似乎实现了引用语义(它本质上是一个标头和指向数据块的指针),但它可以实现为提供合理的cv::Mat正确性。它不会通过我参与的任何代码审查。

答案 1 :(得分:4)

根据文档,cv::Mat是关于矩阵的元数据,实际数据是共享的和引用计数的,如std::shared_ptr

因此const cv::Matconst std::shared_ptr<double>类似 - 您无法将其绑定到新位置,但您可以修改指向的数据。

你正在寻找相当于std::shared_ptr<const double>的东西,在阅读the documentation后,看起来并不存在任何这样的东西。更奇怪的是,可以将“只读”InputArray参数转换为Mat智能指针。因此,要么创建禁止修改的Mat智能指针的秘密方法,要么InputArray根本不是只读。

正如juanchopanza所说,这应该没有进行设计审查。提供具有共享数据所有权的智能指针类都很好,但是:

  • 如果您有共享语义,则类名应该反映出来。如果MPtrstd::shared_ptr一样工作,那么没有人会感到困惑。
  • 只读和写入之间的混淆更深入,从InputArrayMat的转换证明了这一点。

答案 2 :(得分:0)

const Foo& operator += ( const Foo& obj) const
{
    this->ptr[0] += obj.ptr[0];
    return *this;
}

你可以告诉,这个操作员:

1)将const引用返回给Foo;

2)接受对Foo的const引用;

3)不会更改声明的类中的任何成员。

这是合法的,因为在这里你改变了对象,ptr指向,但不是ptr本身(它仍然指向同一个位置)。传递给changeConst函数的值可以被+ =运算符接受。这些函数不会改变Foo类中的任何内容,因为它只有一个指针。但是,指针指向IS的数据已更改。

如果您在努力了解const的工作原理,我建议您观看this视频。