我是否应该将成员函数声明为`const`,即使它修改了指针所指向的内容?

时间:2018-03-15 09:40:30

标签: c++ const public

考虑以下简单(人为)代码示例:

#include <iostream>

class Foo {
  std::size_t size;
  char *buf;

public:
  Foo(std::size_t s) {
    size = s;
    buf = new char[size];
    for (int i = 0; i < size; i++) {
      buf[i] = 'a';
    }
  } 

  void hexprint() const {
    for (int i = 0; i < size; i++) {
      std::cout << buf[i];
    }
    std::cout << std::endl;
  }

  char &operator[](std::size_t pos) const {
    // TODO: check pos
    return buf[pos];
  }  

  void calcSomething(int param, char *result) const {
    // calcuate something with param
    *result = 'b';
  }
};

int main() {
  const Foo foo(3);
  char *c = &foo[0];
  char result;

  // do something with c

  foo.hexprint(); // output aaa

  foo.doSomething(56, c); // upps passed in c, instead of &result
                          // still compiler was happy

  foo.hexprint(); // output baa

  // called only const functions but the const object
  // is still mutated
}

calcSomething的成员函数Foo计算某些内容并将结果存储在指针result指向的内容中。 现在从编译器的角度来看,这个成员函数可以标记为const。但由于修改指针所指向的内容,因此有可能仍然可以通过指针修改对象(如示例中所示)。

现在我的问题是:

  1. 我是否应该将calcSomething限定为const,即使它修改指针指向的内容,只是因为编译器允许它?
  2. calcSomething定格为const对编译器的优化过程更有帮助吗?
  3. 另一方面,可以将calcSomething限定为const误导客户认为它永远不会改变它被调用的对象?特别是,如果不明显有涉及指针?
  4. 当我可以安全地将(成员)职能限定为const时,是否有任何规则要遵循?

5 个答案:

答案 0 :(得分:3)

将成员函数限定为function custom_webform_comments_status_dbupdater($data) { global $user; //Insert values into database $insert = db_insert('custom_webform_submission_status') ->fields(array( 'id' => NULL, 'status' => $data['status'], 'submit_time' => date("Y-m-d H:i:s"), 'nid' => $data['nid'], 'sid' => $data['sid'], 'user' => serialize($user) ))->execute(); if($insert) { global $user; $params = array( 'body' => $message, 'subject' => 'Website Information Request', 'headers'=>'simple', ); $message = drupal_mail('custom_webform_comments', 'custom_webform_comments_email', $user->mail, language_default(), $params, 'test@example.com', TRUE); if (!empty($message['result'])) { watchdog('mail', 'Mail sent Successfully (from %from to %to) for status update', array('%from' => $message['from'], '%to' => $message['to']), WATCHDOG_NOTICE); //drupal_set_message("Mail sent!"); } else{ watchdog('mail', 'Error sending e-mail (from %from to %to).', array('%from' => $message['from'], '%to' => $message['to']), WATCHDOG_ERROR); drupal_set_message(t('Unable to send e-mail. Contact the site administrator if the problem persists.'), 'error'); } } return $insert; } 并不意味着它没有任何副作用,但它并没有修改其对象的逻辑状态,至少通过{{1 }}-指针。请记住,const适用于this

const限定为*this不太可能对优化程序产生任何影响。如果它在逻辑上是正确的,请这样做。

当然有些人不清楚对象的状态是什么,或者逻辑*this和物理const之间有什么区别,所以有些人可能会感到困惑。

无论如何,您确定const应该成为公共界面的一部分吗?这似乎是将漏洞置于漏洞抽象中。

答案 1 :(得分:1)

  

我是否应该将calcSomething限定为const,即使它修改指针所指向的内容,只是因为编译器允许它?

是。对象本身不会被修改(至少通过this指针!),所以没关系。

  

将calcSomething限定为const对编译器的优化过程更有帮助吗?

仅仅因为this是当前函数中的const并不意味着同时调用非const函数(例如,在另一个线程中)。所以编译器可以做出的假设不应该太多,尽管我不能排除有一些选项而不偷看标准......

  

另一方面,可以将calcSomething限定为const误导客户认为它永远不会改变它被调用的对象吗?特别是,如果涉及指针并不明显?

const是一个契约,一个承诺:声明为const的函数不会通过this指针改变被调用的对象。 this隐含在函数内的const;你仍然可以把它扔掉并且无论如何都要修改它,但是你打破了合同,然后是承诺!并且:对象可以有mutable个成员 - 即使对象是常量,也可以更改这些成员...

const(例如我上面的线程示例)没有给出任何进一步的保证,并且没有人应该假定合同中保证的更多。谁做了 - 自己的错......

  

当我可以安全地将(成员)函数限定为const时,是否有任何规则要遵循?

非常简单:除非你修改一些不可变的成员,否则你的函数是const ...

参考你的例子:

a.calcSomething(56, &a.i);

只要a不是常量,即使a以这种方式间接修改,这也没问题。函数本身只跟一个指针,它指向的位置无关紧要。如果a是const,则无法调用此函数,因为a.i也将是const,并且您将尝试将指向const的指针指定给指向非const的指针。 ..

旁注:有例外,但在大多数情况下,成员变量代表对象的某种内部状态,然后将它们公开不是一个好主意...

答案 2 :(得分:0)

由于ipublic成员,因此设置了腐烂。如果不是,那么您将无法在呼叫站点传递&a.i

如果您未明确修改功能正文中的成员数据,则应将您的职能限定为const

答案 3 :(得分:0)

您没有修改方法中的成员,因此它应该是const。您的示例很好,因为a不是const。如果你尝试了这个,你会得到正确的错误:

const A a;
a.calcSomething(56, &a.i); // yay stupid mistake isnt possible

答案 4 :(得分:0)

是!

论点:

int *result

是指向外部变量的指针。所以它可以被修改。

const方法中,您无法修改类的内部状态。

class A {
public:
  int i{0};
  int my_result;


  void calcSomething(int param, int *result) const {
    // calcuate something with param
    *result = 42;  // Ok
    this->my_result = 42 ; /// ERROR: because the method is const.
  }
};