Можно ли отложить инициализацию константной переменной в C ++, например, в «пустой финальной» версии Java? - PullRequest
2 голосов
/ 01 апреля 2019

В Java мы можем объявить переменную blank final и инициализировать ее позже.Компилятор обеспечит инициализацию ровно один раз - сбой при инициализации или двойной инициализации являются ошибками во время компиляции.Например:

public int bar() {
   return 66;
}

public void foo() {
    final int x; // declare the variable
    ...
    x = bar(); // initialization only once
}

В Java компилятор может гарантировать, что x определенно не назначен ни в каком пути кода до его первого назначения, и может гарантировать, что он определенно никогда не будет назначен во второй раз прилюбой путь к коду.(См. Глава 16, Определенное присвоение , Спецификации языка Java для получения дополнительной информации.)

Как мы можем достичь аналогичного поведения в C ++?Можно ли объявить переменную const, но отложить ее инициализацию?(Без исключения спецификатора const.)

Ответы [ 2 ]

3 голосов
/ 01 апреля 2019

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

template<typename T>
class once
{
private: 
    std::aligned_storage_t<sizeof(T), alignof(T)> data;
    T* ptr = nullptr;
public:
    once() = default;
    ~once()
    {
        if(ptr) // it is initialized so call the destructor
            ptr->~T();
        // optionally you can add
        // throw("a once<T> must be initialized once");
        // this can help to enforce that the object is actually initialized as you'll get a runtime exception in code that does not do so
    }
    template<typename U>
    once& operator =(U&& value)
    {
        if (!ptr) // it is not initialized so call constructor
        {
            ptr = new(&data) T(std::forward<U>(value));
        }
        else
            throw ("can only assign to a once<T> once.");
        return *this;
    }
    operator const T&()
    {
        return *ptr;
    }

};

, а затем вы будете использовать его как

int main()
{
    once<int> foo;
    if (1 < -1)
        foo = 21;
    else
        foo = 42;
    std::cout << foo;
    //foo = 23; // uncomment this to get an exception.
}
3 голосов
/ 01 апреля 2019

Невозможно инициализировать const, кроме случаев, когда он определен. Вы должны найти способ узнать его значение там, где оно определено. Если значение x трудно определить, рассмотрите возможность использования результата, например

const int x = calc_x();

или закрытие типа

const int x = []() { /* code to calculate x's value */ }();

const ness является частью типа объекта, и тип объекта не может быть изменен ни при каких обстоятельствах, поэтому либо x равен const, и вы не можете инициализировать его позже, либо x нет const на всех.

Можно создать оболочку class, которая будет имитировать это, но в лучшем случае вы получите ошибку во время выполнения.

Обратите внимание, что может показаться, что существует решение в форме const_cast, но это предполагает, что рассматриваемый объект на самом деле не const. В случае const int x нет никакого способа юридически изменить его значение после его инициализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...