C++ 如何在函数声明中使用const

C++ 如何在函数声明中使用const,c++,opencv,reference,constants,C++,Opencv,Reference,Constants,在opencv中,我碰巧修改了一个作为常量传递给函数的变量: void someFunction(const cv::Mat matrix) { double value = 5.0; matrix /= value; } 它不仅可以编译,而且在调用someFunctionmatrix之后,矩阵仍然会被修改,即使我还没有将矩阵作为引用传递。我对这段要编译的代码的解释是,我实际上并没有在某个函数中更改矩阵的任何成员,而是更改由矩阵的指针dataof所指向的地址的内容,但我不是很确定。 由

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

void someFunction(const cv::Mat matrix)
{
  double value = 5.0;
  matrix /= value;
}
它不仅可以编译,而且在调用someFunctionmatrix之后,矩阵仍然会被修改,即使我还没有将矩阵作为引用传递。我对这段要编译的代码的解释是,我实际上并没有在某个函数中更改矩阵的任何成员,而是更改由矩阵的指针dataof所指向的地址的内容,但我不是很确定。 由于有点困惑,我试图在一个小程序中再现这种情况:

#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;
}
它不编译。为什么会这样?这一发现使我产生了许多疑问。有没有办法防止函数中指针内容的更改?返回常量引用常量Foo&的函数的含义是什么?当声明函数const时,应该使用什么?简而言之,我应该如何在函数声明中使用const?

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

const版本编译并且似乎做了一些违反直觉的事情的原因是,您正在修改Mat指向的对象,假设您是指/=或Foo对象,但您没有修改数据成员本身,即指针

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

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

const Foo& operator += ( const Foo& obj) const
{
    this->ptr[0] += obj.ptr[0];
    return *this;
}
const版本编译并且似乎做了一些违反直觉的事情的原因是,您正在修改Mat指向的对象,假设您是指/=或Foo对象,但您没有修改数据成员本身,即指针

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

const Foo& operator += ( const Foo& obj) const
{
    this->ptr[0] += obj.ptr[0];
    return *this;
}
您可以告诉,这个操作员:

1返回对Foo的常量引用

2接受对Foo的常量引用

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

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

我建议你看视频,如果你很难理解const是如何工作的

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

1返回对Foo的常量引用

2接受对Foo的常量引用

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

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


如果你很难理解const是如何工作的,我建议你观看视频。

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

因此,const cv::Mat与const std::shared_ptr类似——您不能将其绑定到新位置,但可以修改指向的数据

您正在寻找与std::shared_ptr等价的东西,在阅读之后,它看起来并不存在。更奇怪的是,可以将只读InputArray参数转换为Mat智能指针。所以要么有一种秘密的方法来创建禁止修改的Mat智能指针,要么InputArray根本就不是只读的

正如juanchopanza所说,这本应该在设计审查中失败。提供具有数据共享所有权的智能指针类很好,但是:

如果您有共享语义,那么类名应该反映这一点。如果MPtr像std::shared\u ptr那样工作,没有人会感到困惑。 从InputArray到Mat的转换可以看出,只读和可写之间的混淆要深刻得多。
根据文档,cv::Mat是关于矩阵w的元数据 实际数据共享和引用计数,如std::shared\u ptr

因此,const cv::Mat与const std::shared_ptr类似——您不能将其绑定到新位置,但可以修改指向的数据

您正在寻找与std::shared_ptr等价的东西,在阅读之后,它看起来并不存在。更奇怪的是,可以将只读InputArray参数转换为Mat智能指针。所以要么有一种秘密的方法来创建禁止修改的Mat智能指针,要么InputArray根本就不是只读的

正如juanchopanza所说,这本应该在设计审查中失败。提供具有数据共享所有权的智能指针类很好,但是:

如果您有共享语义,那么类名应该反映这一点。如果MPtr像std::shared\u ptr那样工作,没有人会感到困惑。 从InputArray到Mat的转换可以看出,只读和可写之间的混淆要深刻得多。
我不确定矩阵\=值如何;编译。@chris至少可以说cv::Mat的语义很奇怪。@juanchopanza,也许/=可以,但不是\=AFAIK。@chris是的,甚至cv::Mat也不应该对\=”有意义。@Manu:什么?By value const对于防止意外修改非常有用,假设对象的实现是合理的,不像这里的示例,选择成员函数的const版本的首选项,通常会创建优化机会;编译。@chris至少可以说cv::Mat的语义很奇怪。@juanchopanza,也许/=可以,但不是\=AFAIK。@chris是的,甚至cv::Mat也不应该对\=”有意义。@Manu:什么?By value const对于防止意外修改非常有用,假设对象实现合理,不像这里的示例,为成员函数的const版本选择首选项,通常会创建优化机会。除非您的对象是指向foo的指针的表示,它应该相应地命名。复制名为Foo的对象不应只产生foogacity的一个表示形式。除非您的对象是指向Foo的指针的表示形式,否则应相应地命名它。复制名为Foo的对象不应只产生foogacity的一种表示形式。