E laserattack

programming for fun

Указатели на переменные базовых типов

Случай 1

int a = 10;
int *p = &a; // OK
p--; // OK
p++; // OK
(*p)++; // OK

Случай 2

const int a = 10;
int *p = &a; // error: invalid conversion from 'const int*' to 'int*'
p--;
p++;
(*p)++;

Случай 3

const int a = 10;
const int *p = &a; // OK
p--; // OK
p++; // OK
(*p)++; // error: increment of read-only location '* p'

сначала подумал что read-only location означает RO-секцию типо .rodata, куда поместился литерал. но в общем случае это то не означает, потому что тут ошибка та же

void f(const int *p) {
    (*p)++; // error: increment of read-only location '* p'
}

т.е. read-only тут не факт что уровня ОС, под read-only может иметься в виду гарантия компилятора не менять константу

Случай 4

int a = 10;
int *const p = &a; // OK
(*p)++; // OK
p--; // error: decrement of read-only variable 'p'

Случай 5

const int a = 10;
const int *const p = &a;
(*p)++; // error: increment of read-only location '*(const int*)p'
p--; // error: decrement of read-only variable 'p'

Пользовательские типы: константные и неконстантные объекты

Случай 1

struct Data {
    int data;
};

int main() {
    Data a; // OK
    const Data b; // error: uninitialized 'const b'
                  // note: 'const struct Data' has no user-provided default constructor
}

Если определяю конструктор, то все ок

struct Data {
    int data;
    Data() : data() {}
};

int main() {
    Data a; // OK
    const Data b; // OK
}

Случай 2

struct Data {
    int data;
    Data() : data() {}
};

int main() {
    Data a;
    const Data b;
    a.data = 1;
    b.data = 1; // error: assignment of member 'Data::data' in read-only object
}

если поле помечено как mutable то его можно менять даже если объект константный

struct Data {
    mutable int data;
    Data() : data() {}
};

int main() {
    Data a;
    const Data b;
    a.data = 1;
    b.data = 1;
}

Случай 3

struct Data {
    int *data;
    Data() : data(new int[3]) {}
    ~Data() { delete[] data; }
};

int main() {
    Data a; // OK
    const Data b; // OK
    a.data[1] = 1; // OK
    b.data[1] = 1; // OK
}

Случай 4

Вывод: не-const метод нельзя вызвать на const объекте

матчасть: любой метод неявно принимает адрес объекта, т.е. obj.method() компилятор превращает образно говоря в Class::method(&obj)

#include <iostream>

struct Data {
    int *data;
    int len;
    Data() {
        data = new int[3]{1, 2, 3};
        len = 3;
    }
    ~Data() { delete[] data; }
    void print() {
        for (int i = 0; i < len; i++) {
            std::cout << data[i];
        }
    }
};

int main() {
    const Data a;
    a.print(); // error: passing 'const Data' as 'this' argument discards qualifiers
}

Когда вызывается a.print() на const Data a:

если определяю метод как константный то все ок

#include <iostream>

struct Data {
    int *data;
    int len;
    Data() {
        data = new int[3]{1, 2, 3};
        len = 3;
    }
    ~Data() { delete[] data; }
    void print() const {
        for (int i = 0; i < len; i++) {
            std::cout << data[i];
        }
    }
};

int main() {
    const Data a;
    a.print(); // OK
}

если не менять метод то можно еще так

#include <iostream>

struct Data {
    int *data;
    int len;
    Data() {
        data = new int[3]{1, 2, 3};
        len = 3;
    }
    ~Data() { delete[] data; }
    void print() {
        for (int i = 0; i < len; i++) {
            std::cout << data[i];
        }
    }
};

int main() {
    const Data a; // OK
    const_cast<Data&>(a).print(); // OK
}

Случай 5

struct Data {
    void print() {
        std::cout << "non-const\n";
    }

    void print() const {
        std::cout << "const\n";
    }
};

int main() {
    Data a;
    const Data b;

    a.print(); // "non-const"
    b.print(); // "const"
}

Posted on 25th August 2026