Подтвердить что ты не робот

Могу ли я сделать переменную _const с этого момента?

Я использую библиотеку, у которой есть класс с функцией init, отличной от его конструктора. Каждый раз, когда я делаю новый экземпляр, мне нужно вызвать, например:

MyClass a;
a.init();

Так как init не const, это мешает мне создавать экземпляры const (я не могу написать const MyClass a). Есть ли способ вызвать init, а затем объявить из "here on out" (я думаю, для остальной части области) моя переменная const?

Это работает, но полагается на не касание исходной переменной:

MyClass dont_touch;
dont_touch.init();
const MyClass & a = dont_touch;
4b9b3361

Ответ 1

Если вы используете С++ 11, вы можете использовать функцию лямбда

const MyClass ConstantVal = []{ 
    MyClass a;
    a.init(); 
    return a; 
}();

Это позволяет сохранить инициализацию на месте, не предоставляя внешний доступ к изменяемому объекту. смотрите также: http://herbsutter.com/2013/04/05/complex-initialization-for-a-const-variable/

Ответ 2

Вы можете создать класс-оболочку и использовать это вместо.

Если MyClass имеет виртуальный деструктор, вы можете чувствовать себя безопасно, исходя из этого:

class WrapperClass : public MyClass 
{
public:
    WrapperClass()
    {
        init(); // Let hope this function doesn't throw
    }
};

Или напишите класс, содержащий экземпляр MyClass

class WrapperClass
{
public:
    WrapperClass()
    {
        m_myClass.init(); // Let hope this function doesn't throw
    }
    operator MyClass&() {return m_myClass;}
    operator const MyClass&() const {return m_myClass;}
private:
    MyClass m_myClass;
};

Или напишите шаблон, чтобы решить эту общую проблему, используя одно из двух вышеприведенных решений: например.

template <class T> class WrapperClass : public T
{
public:
    WrapperClass()
    {
        T::init();
    }
};

typedef WrapperClass<MyClass> WrapperClass;

Ответ 3

Создайте функцию, которая обертывает первые две строки и дает вам объект, который готов к работе.

MyClass makeMyClass()
{
   MyClass a;
   a.init();
   return a;
}

// Now you can construct a const object or non-const object.
const MyClass a = makeMyClass();
MyClass b = makeMyClass(); 

Обновление

Использование makeMyClass() включает в себя создание и уничтожение временного объекта каждый раз, когда вызывается функция. Если это становится значительной стоимостью, makeMyClass() можно изменить на:

MyClass const& makeMyClass()
{
   static bool inited = false;
   static MyClass a;
   if ( !inited )
   {
     inited = true;
     a.init();
   }
   return a;
}

Это использование, как описано выше, будет продолжать работать. Кроме того, один раз также можно сделать следующее:

const MyClass& c = makeMyClass();

Ответ 4

Вы можете сделать это довольно просто, даже без С++ 11 и lambdas:

const MyClass a;
{
    MyClass _a;
    _a.init();
    std::swap(const_cast<MyClass&>(a), _a);
}

Использование const_cast, по общему признанию, немного взломанно, но оно ничего не сломает, поскольку const является довольно слабым спецификатором. В то же время он довольно эффективен, поскольку объект MyClass заменяется только, а не копируется (наиболее разумные объекты с дорогостоящим копированием должны предоставлять функцию swap и вводить перегрузку std::swap).

Без броска для этого потребуется помощник:

struct Construct_Init {
    operator MyClass() const
    {
        MyClass a;
        a.init();
        return a;
    }
};
const MyClass a = Construct_Init();

Это может быть как в функции (структура Construct_Init не должна быть объявлена ​​в области пространства имен), но она немного длиннее. Копия объекта может быть оптимизирована или не удалена с помощью копирования.

Обратите внимание, что в обоих случаях возвращаемое значение init() теряется. Если он возвращает логическое значение, где true является успешным, а false - ошибкой, лучше:

if(!a.init())
    throw std::runtime_error("MyClass init failed");

Или просто обязательно обработайте ошибки соответствующим образом.