константная функция c ++ - PullRequest
2 голосов
/ 02 июля 2010

Я читаю книгу под названием «Эффективный C ++, второе издание», в которой рассказывается о функциях-членах const и о том, как у вас есть побитовая константность и концептуальная константность.побитовое постоянство, которое заключается в том, что вы не можете изменять члены-данные объекта внутри функции-члена 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 ]

7 голосов
/ 02 июля 2010

Нарушение прав доступа связано с тем, что вы пытаетесь изменить строковый литерал. Ваш код эквивалентен:

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

, что недопустимо в C и C ++ - ничего общего с константными функциями-членами.

2 голосов
/ 02 июля 2010

Вы получаете нарушение доступа только потому, что указатель char* указывает на строковый литерал. Изменение строкового литерала - неопределенное поведение (AV в вашем случае), оно не имеет ничего общего с const-правильностью.

0 голосов
/ 02 июля 2010

В вашем примере вы не меняете 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 указывает на строковый литерал, который вы не можете изменять.

0 голосов
/ 02 июля 2010

То, что вы делаете, это неопределенное поведение. Вы отбрасываете постоянство и пытаетесь изменить постоянное значение. Если этот пример был скопирован из книги «как есть», значит книга неверна.

Что разрешено делать с 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

Причина, по которой вы не можете отбросить константу из ссылки на реальный константный объект, заключается в том, что компилятор может решить поместить объект в постоянную память, и в этом случае операция может завершиться ошибкой различными способами (убивая приложение, игнорируя изменение ...)

...