考虑以下简单(人为)代码示例:
#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
。但由于修改指针所指向的内容,因此有可能仍然可以通过指针修改对象(如示例中所示)。
现在我的问题是:
calcSomething
限定为const
,即使它修改指针指向的内容,只是因为编译器允许它?calcSomething
定格为const
对编译器的优化过程更有帮助吗?calcSomething
限定为const
误导客户认为它永远不会改变它被调用的对象?特别是,如果不明显有涉及指针?const
时,是否有任何规则要遵循?答案 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)
由于i
是public
成员,因此设置了腐烂。如果不是,那么您将无法在呼叫站点传递&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.
}
};