2

我正在阅读一本名为“Effective C++, Second Edition”的书,其中讨论了 const 成员函数以及如何拥有按位 const 和概念 const 。

它说大多数编译器将使用按位 const-ness,即您不能在 const 成员函数内更改对象的数据成员。

然后有一个成员函数的例子,它在 const 测试中似乎没有按位运行。

它是这样的:

#include "stdafx.h"
#include <string>
#include <iostream.h>

using namespace std;

class mystring
{

public:
    mystring(const char* value);

    operator char *() const { return data; }

private:
    char * data;
};

mystring::mystring(const char * value)
{

    mystring::data = const_cast<char*>(value);
}


int main(int argc, char* argv[])
{
    const mystring s = "Hello";

    char * nasty = s;

    *nasty = 'M';

    printf("s: %c", s);

    return 0;
}

当它运行时,它在我的书中说它应该允许你改变 的值s,即使它的const. 这是因为 char* 数据指向的值与指向的值相同const char**data在这种情况下不是const

但是尝试在 MS VC++ 6.0 中运行它,它会在行引发访问冲突 *nasty = 'M';

有人可以解释发生了什么吗?我想我错过了什么?

在我看来,因为我们有一个 const mystring s,我们不应该能够改变它,但是它在书中所说的似乎很尴尬。

4

4 回答 4

7

访问冲突是因为您尝试更改字符串文字。您的代码相当于:

char * p = "Hello";
* p = 'M';

这在 C 和 C++ 中都是非法的 - 与 const 成员函数无关。

于 2010-07-02T11:48:45.837 回答
2

仅因为char*指针指向字符串文字,您才会遇到访问冲突。更改字符串文字是未定义的行为(在您的情况下为 AV),它与 const 正确性无关。

于 2010-07-02T11:49:47.320 回答
0

你正在做的是未定义的行为。您正在抛弃 const-ness 并尝试修改常量值。如果那个例子是从书中照原样复制的,那么这本书就是错的。

合法的做法const_cast<>是将常量从常量指针/引用丢弃到非常量对象:

int i = 5;
int const & ir = i;
const_cast<int&>(ir) = 7; // valid
int const * ip = &i;
*const_cast<int*>(ip) = 9; // valid

const int c = 11;
int const & cr = c;
const_cast<int&>(cr) = 13; // Undefined behavior

您不能从对真实 const 对象的引用中抛弃 const-ness 的原因是编译器可以决定将对象放在只读内存中,在这种情况下,操作可能会以不同的方式失败(杀死应用程序,忽略改变...)

于 2010-07-02T11:55:21.643 回答
0

在您的示例中,您不会更改s,而是尝试更改成员变量s指向的内存。由于您可以const在很多地方放置 ,因此您必须小心您实际声明的内容const

您的成员函数operator char*() const不允许更改任何成员变量。尝试一下operator char *() const { data = "something else"; return data; },您的编译器会告诉您不允许修改data. 但是,在这种情况下,您只需返回data而不进行修改。这是允许的。您甚至可以更改data指向的内存,如operator char *() const { *data = 'M'; return data; }. 但是,这在您的上下文中失败,因为data指向不允许更改的字符串文字。

于 2010-07-02T12:05:39.433 回答