Есть ли эффективный способ сделать ссылку на константы фактически const вместо только для чтения?

Давайте посмотрим на следующий код C ++:

#include <iostream>

int main()
{
int z = 2;

class A {
public:
const int & x;
A(const int & x) : x(x) {}
void show(){
std::cout << "x=" << this->x << std::endl ;
}
} a(z);

a.show();
z = 3;
a.show();
}

Программа печатает: 2 и 3

Это ясно показывает, что, хотя внутри класса A x нельзя изменить, это просто означает, что он только для чтения, потому что я могу изменить его значение извне.

Конечно, я могу сделать это копией, хранящейся в классе A, но мне интересно, есть ли (или есть ли предложение?) Способ сказать классу A, что член x будет действительно постоянным, а не просто прочитанным только со смыслом обещания, что внешний код не изменит его?

На мой взгляд это выглядит как нечто, связанное со значением C ограничивать Ключевое слово, но я еще не слышал о такой возможности C ++. Вы ?

4

Решение

Констанция является атрибутом фактической переменной.

Семестр const int& x просто означает «x — это ссылка на int, которую он не изменит», и, конечно, компилятор обеспечивает это.

Если вы хотите, чтобы фактическая переменная, на которую ссылается x, была константой, просто объявите ее так:

#include <iostream>

int main()
{
const int z = 2;    // declared const. Nothing may ever modify it

class A {
public:
const int & x;
A(const int & x) : x(x) {}
void show(){
std::cout << "x=" << this->x << std::endl ;
}
} a(z);

a.show();
z = 3;        // this is a logic error, caught by the compiler.
a.show();
}

правильная компиляция выдает ошибку:

./const.cpp:41:7: error: read-only variable is not assignable
z = 3;
~ ^
1 error generated.
4

Другие решения

Вы ищете D’s immutable Ключевое слово, которое было введено как новое понятие в этом языке именно потому, что, к сожалению, ответ — нет: его нет в C ++.

3

Constness в C ++ не означает неизменность, но то, что рассматриваемая переменная доступна только для чтения. Это может все еще быть изменено другими частями программы. Я понимаю ваш вопрос относительно того, возможно ли обеспечить истинную неизменность в вызываемой функции, не зная, что делает вызывающая сторона.

Конечно, вы можете создать класс-оболочку шаблона, который выполняет задачу:

template <typename T>
class Immutable
{
public:
template <typename ...Args>
Immutable( Args&&...args )
: x( std::forward<Args>(args)... )
{}

operator const T &() const
{
return x;
}

private:
const T x;
};

Пока ты не reinterpret_cast или же const_cast у вас будут действительно неизменные объекты, когда вы их оберните Immutable<T>,

Однако, если у вас есть постоянная ссылка на некоторый объект, невозможно определить, имеет ли какая-либо другая часть программы непостоянный доступ к объекту. Фактически, базовый объект может быть глобальной или статической переменной, к которой у вас есть доступ только для чтения, но функции, которые вы вызываете, могут по-прежнему изменять его.

Это не может случиться с Immutable<T> объект. Однако, используя Immutable<T> может навязать вам дополнительную операцию копирования. Вы должны судить себя, можете ли вы жить с этим и оправдывает ли выгода прибыль.

Наличие функции требует const Immutable<Something> & вместо const Something & в качестве аргумента влияет на вызывающий код. Операция копирования может быть запущена. Кроме того, вы можете попросить Immutable<Something> & без const, Тогда никакие случайные копии не будут запущены, но вызывающий код должен передать ссылку на Immutable<Something> объект. И это правильно, потому что, если абонент получил const & в качестве аргумента вызывающая сторона не знает, может ли объект быть изменен кем-то еще в программе. Вызывающий объект должен создать сам объект или требовать, чтобы неизменный объект передавался ему в качестве ссылки.

Ваш оригинальный вопрос

Вот ваша оригинальная проблема с Immutable<int> & вместо const int &,

#include <iostream>

int main()
{
Immutable<int> z = 2;

class A {
public:
const Immutable<int> & x;
A(Immutable<int> & x) : x(x) {}
void show(){
std::cout << "x=" << this->x << std::endl ;
}
} a(z);

a.show();
//z = 3; // this would fail
a.show();
}

Другой пример

Вот как это работает: если вы пишете

void printAndIncrementAndPrint( int & i1, const int & i2 )
{
std::cout << i2 << std::endl;
++i1;
std::cout << i2 << std::endl;
}

int main()
{
int i = 0;
printAndIncrementAndPrint( i, i );
}

тогда он напечатает

0
1

в консоль. Если вы замените второй аргумент printAndIncrementAndPrint() с const Immutable<int> & i2 и оставьте то же самое, тогда копия будет запущена, и она напечатает

0
0

на консоль. Вы не можете пройти и Immutable<int> к функции и int & к тем же базовым данным, не нарушая систему типов, используя const_cast или же reinterpret_cast,

2

Я думаю, что это проблема дизайна для программистов, а не язык. const переменная означает для любого пользователя этой переменной, они не должны изменять значение этой переменной. Наш компилятор достаточно умен, чтобы помочь нам убедиться в этом. Так A пользователь z и если вы хотите A знать, что A::x ссылки на const переменная, то вы должны сделать z const int, const reference это просто сохранить договор между пользователем и провайдером.

0
По вопросам рекламы [email protected]