Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

value_initialized

Boost , ,

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Header <boost/utility/value_init.hpp>

Contents

Rationale
Introduction
Details
Types and objects
Acknowledgements


Rationale

Конструирование и инициализация объектов общим способом в C++ затруднена. Проблема в том, что существует несколько различных правил, которые применяются для инициализации. В зависимости от типа, значение вновь построенного объекта может быть нулевым (логически 0), построенным по умолчанию (с использованием конструктора по умолчанию) или неопределенным. При написании общего кода эту проблему необходимо решать. Шаблон<value_initialized>обеспечивает решение с последовательным синтаксисом для инициализации значений скалярных, союзных и классовых типов. Кроме того,<value_initialized>предлагает обходной путь к различным вопросам компилятора, касающимся инициализации ценности. Кроме того, предусмотрен объект<const>,<initialized_value>, чтобы избежать повторения имени типа при извлечении значения из объекта<value_initialized<T>>.

Introduction

Существуют различные способы инициализации переменной в C++. Следующие декларациимогутиметь локальную переменную, инициализированную до значения по умолчанию:<

  T1 var1;
  T2 var2 = 0;
  T3 var3 = {};
  T4 var4 = T4();
>К сожалению, правильно ли в любом из этих заявлений инициализируется переменная, во многом зависит от ее типа. Первая декларация действительна для любоготипа DefaultConstructible(по определению). Однако это не всегда инициализация! Он правильно инициализирует переменную, когда она является экземпляром класса, и автор класса предоставил надлежащий конструктор по умолчанию. С другой стороны, значение<var1>являетсянеопределенным, когда его тип является арифметическим типом, таким как<int>,<float>или<char>. Арифметическая переменная, конечно, инициализирована правильно второй декларацией<T2 var2 = 0>. Но эта форма инициализации обычно не работает для типа класса (если класс не был специально написан для поддержки инициализации). Третья форма<T3 var3 = {}>инициализирует агрегат, как правило, массив «С-стиль»<struct>или «С-стиль». Однако синтаксис не допускается для класса, который имеет явно объявленный конструктор. (Остерегайтесь предстоящего изменения языка C++, Бьярн Страуструп и др.1)!) Четвёртая форма является наиболее общей из них, так как её можно использовать для инициализации типов арифметики, типов классов, агрегатов, указателей и других типов. Заявление<T4 var4 = T4()>следует читать следующим образом: Сначала создается временный объект<T4()>. Этот объектинициализирован. Затем временный объект копируется в названную переменную<var4>. После этого временное уничтожается. Хотя копирование и уничтожение, вероятно, будут оптимизированы, C++ по-прежнему требует, чтобы тип<T4>былCopyConstructible.<T4>]]]][[править править код]. Класс не может быть CopyConstructible, например, потому, что он может иметь частный и неопределенный конструктор копий, или потому, что он может быть получен изboost::noncopyable. Скотт Мейерс2объясняет, почему класс определяется именно так.

Есть и другой, менее очевидный недостаток четвертой формы<T4 var4 = T4()>: Он страдает от различныхпроблем компилятора, в результате чего переменная остается неинициализированной в некоторых конкретных случаях компилятора.

Шаблон<value_initialized>предлагает общий способ инициализации объекта, как<T4 var4 = T4()>, но не требует, чтобы его тип был CopyConstructible. И он предлагает обходные пути к тем вопросам компилятора, касающимся инициализации стоимости! Он позволяет получить инициализированную переменную любого типа; онтолькотребует, чтобы тип был конструктивным по умолчанию. Правильноинициализированныйобъект типа<T>сконструирован следующим заявлением:<

  value_initialized<T> var;
>

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

Объект<const><initialized_value>позволяет инициировать значение переменной следующим образом:<

  T var = initialized_value ;
>Эта форма инициализации семантически эквивалентна<T4 var4 = T4()>, но устойчива к вышеупомянутым проблемам компилятора.

Details

Стандарт C++ [3] содержит определения<zero-initialization>и<default-initialization>. Неофициально нулевая инициализация означает, что объекту присваивается начальное значение 0 (превращено в тип), а инициализация по умолчанию означает, что типы POD [4] являются нулевыми инициализацией, в то время как типы класса, не относящиеся к PoD, инициализируются с соответствующими конструкторами по умолчанию. Декларацияможет содержать инициализатор, который определяет начальное значение объекта. Инициатор может быть просто '()', который гласит, что объект должен быть инициализирован (но см. ниже). Однако еслидекларацияне имеетинициализатораи имеет не<const>, не<static>POD-тип, начальное значение является неопределенным:(см. §8.5, [dcl.init], для точных определений).

int x ; // no initializer. x value is indeterminate.
std::string s ; // no initializer, s is default-constructed.

int y = int() ;
// y is initialized using copy-initialization
// but the temporary uses an empty set of parentheses as the initializer,
// so it is default-constructed.
// A default constructed POD type is zero-initialized,
// therefore, y == 0.

void foo ( std::string ) ;
foo ( std::string() ) ;
// the temporary string is default constructed
// as indicated by the initializer ()

value-initialization

Первоетехническое исправление стандарта C++(TC1), проект которого был опубликован в ноябре 2001 года, представилоCore Issue 178(среди многих других вопросов, конечно).

В этом вопросе была введена новая концепция<value-initialization>(она также закрепила формулировку для нулевой инициализации). Неофициально инициализация значения аналогична инициализации по умолчанию, за исключением того, что в некоторых случаях нестатические элементы данных и подобъекты базового класса также инициализируются значения. Разница заключается в том, что объект, который инициализируется значением, не будет иметь (или, по крайней мере, с меньшей вероятностью будет иметь) неопределенные значения для членов данных и подобъектов базового класса; в отличие от случая объекта, построенного по умолчанию. (см. Основной выпуск 178 для нормативного описания).

Для определения инициализации значения объекта необходимо использовать инициализатор с пустым набором: ().

Как и прежде, декларация без инициализатора указывает инициализацию по умолчанию, а декларация с непустым инициализатором указывает инициализацию копии (=xxx) или прямой (xxx).

template<class T> void eat(T);
int x ; // indeterminate initial value.
std::string s; // default-initialized.
eat ( int() ) ; // value-initialized
eat ( std::string() ) ; // value-initialized

value-initialization syntax

Инициализация значения определяется с помощью (). Однако пустой набор скобок не допускается синтаксисом инициализаторов, поскольку он разбирается как декларация функции, не принимающая аргументов:

int x() ; // declares function int(*)()

Таким образом, пустое () должно быть помещено в другой контекст инициализации.

Альтернативой является использование синтаксиса инициализации копирования:

int x = int() ;

Это отлично подходит для типов POD. Но для типов, не относящихся к классу PoD, копирование-инициализация ищет подходящий конструктор, который может быть, например, копи-конструктором (он также ищет подходящую последовательность преобразования, но это не применимо в этом контексте). Для произвольного неизвестного типа использование этого синтаксиса может не иметь предполагаемого эффекта инициализации значения, потому что мы не знаем, является ли копия из объекта, построенного по умолчанию, точно такой же, как объект, построенный по умолчанию, и компилятор допускается (в некоторых случаях), но никогда не требуется оптимизировать копию.

Одним из возможных общих решений является использование инициализации стоимости нестатического элемента данных:

template<class T> 
struct W
{
// value-initialization of 'data' here.
W() : data() {}
T data ;
} ;
W<int> w ;
// w.data is value-initialized for any type.

Это решение было предложено более ранними версиями класса шаблонов<value_initialized<T>>. К сожалению, этот подход страдал от различных проблем с компилятором.

compiler issues

Various compilers haven't yet fully implemented value-initialization. So when an object should be value-initialized (according to the C++ Standard), it may in practice still be left uninitialized, because of those compiler issues! It's hard to make a general statement on what those issues are like, because they depend on the compiler you are using, its version number, and the type of object you would like to have value-initialized. All compilers we have tested so far support value-initialization for arithmetic types properly. However, various compilers may leave some types of aggregates uninitialized, when they should be value-initialized. Value-initialization of objects of a pointer-to-member type may also go wrong on various compilers.

На момент написания, в мае 2010 года, в текущих выпусках компилятора все еще есть следующие проблемы, связанные с инициализацией стоимости:

Обратите внимание, что все известные проблемы GCC, касающиеся инициализации стоимости, исправлены с помощью версии 4.4 GCC, включаяGCC Bug 30111. Кланг также полностью реализовал инициализацию стоимости, насколько нам известно, теперь, когдаКланг Буг 7139зафиксирован.Microsoft Visual Studio Feedback ID 100744, Value-initialization in new-expression
Павел Кузнецов (MetaCommunications Engineering), 2005
  • Microsoft Visual Studio Feedback ID 484295, VC++ не ценит инициализацию членов производных классов без пользовательского конструктора
  • Microsoft Visual Studio Feedback ID 499606, Присутствие конструктора копий нарушает инициализацию класса участника
    Алекс Вакуленко, 2009
  • Embarcadero/C++Builder Report 83751, Value-initialization: массивы должны иметь каждый элемент value-initialized
    Сообщено Нильсом Деккером (LKEB), 2010
  • Embarcadero/C++Builder Report 83851, Value-initialized temporary triggers internal backend error C1798
    Нильс Деккер, 2010
  • Embarcadero/C++Builder Report 84279, Internal compiler error (F1004), value-initializing member function pointer by "new T()"
    Reported by Niels Dekker, 2010
  • Sun CR 6947016, Sun 5.10 не может инициализировать объект не-POD агрегата.
    Сообщено Стиву Кламажу Нильсом Деккером, 2010
  • IBM XL V10.1 и V11.1 могут не инициировать временный не-POD агрегат.
    Майкл Вонг, Нильс Деккер, 2010
  • Проблема поддержки Intel 589832 Попытка инициализации значения указателя к члену вызывает внутреннюю ошибку в Intel 11.1.
    Джон Мэддок, 2010
  • Note that all known GCC issues regarding value-initialization are fixed with GCC version 4.4, including GCC Bug 30111. Clang also has completely implemented value-initialization, as far as we know, now that Clang Bug 7139 is fixed. [ORIG_END] -->

    Новые версии<value_initialized>(версия 1.35 или выше) предлагают обходные пути к этим проблемам:<value_initialized>теперь может очистить свои внутренние данные, прежде чем строить объект, который он содержит. Это будет сделано для тех компиляторов, которые должны иметь такой обходной путь, на основе макроса дефекта компилятораBOOST_NO_COMPLETE_VALUE_INITIALIZATION.

    Types and objects

    template class value_initialized<T>

    namespace boost {

    template<class T>
    class value_initialized
    {
    public :
    value_initialized() : x() {}
    operator T const &() const { return x ; }
    operator T&() { return x ; }
    T const &data() const { return x ; }
    T& data() { return x ; }
    void swap( value_initialized& );

    private :
    unspecified x ;
    } ;

    template<class T>
    T const& get ( value_initialized<T> const& x )
    {
    return x.data() ;
    }

    template<class T>
    T& get ( value_initialized<T>& x )
    {
    return x.data() ;
    }

    template<class T>
    void swap ( value_initialized<T>& lhs, value_initialized<T>& rhs )
    {
    lhs.swap(rhs) ;
    }

    } // namespace boost

    Объектом этого класса шаблонов является<T>-обертка, конвертируемая в<'T&'>, чей обернутый объект (член данных типа<T>) являетсязначением-инициализациейпри инициализации по умолчанию этого класса обертки:

    int zero = 0 ;
    value_initialized<int> x ;
    assert ( x == zero ) ;

    std::string def ;
    value_initialized< std::string > y ;
    assert ( y == def ) ;

    Целью этой обертки является обеспечение последовательного синтаксиса для инициализации значений скалярных, союзных и классовых типов (POD и неPOD), поскольку правильный синтаксис для инициализации значений варьируется (см.синтаксис инициализации значений).

    К обернутому объекту можно получить доступ либо через оператор преобразования<T&>, функцию члена<data()>, либо функцию нечлена<get()>:

    void watch(int);
    value_initialized<int> x;

    watch(x) ; // operator T& used.
    watch(x.data());
    watch( get(x) ) // function get() used

    И<const>, и<const>объекты могут быть обернуты. Изменяемые объекты могут быть изменены непосредственно из обертки, но постоянные объекты не могут:

    Когда<T>являетсяSwappableтипом,<value_initialized<T>>также является сменным, вызывая его<swap>функцию члена, а также вызывая<boost::swap>.

    value_initialized<int> x ; 
    static_cast<int&>(x) = 1 ; // OK
    get(x) = 1 ; // OK

    value_initialized<int const> y ;
    static_cast<int&>(y) = 1 ; // ERROR: cannot cast to int&
    static_cast<int const&>(y) = 1 ; // ERROR: cannot modify a const value
    get(y) = 1 ; // ERROR: cannot modify a const value

    Warning:

    <value_initialized>реализация Boost версии 1.40.0 и более старой разрешаланеконстдоступ к обернутому объекту из постоянной обертки как оператором преобразования, так и его<data()>функцией-членом. Например:

    value_initialized<int> const x_c ;
    int& xr = x_c ; // OK, conversion to int& available even though x_c is itself const.
    xr = 2 ;

    Причиной этого неясного поведения было то, что некоторые компиляторы не приняли следующий действительный код:

    struct X
    {
    operator int&() ;
    operator int const&() const ;
    };
    X x ;
    (x == 1 ) ; // ERROR HERE!

    Нынешняя версия<value_initialized>больше не имеет такого неясного поведения. Поскольку компиляторы в настоящее время широко поддерживают перегрузку оператора преобразования, имея версию<const>и<non-const>, мы решили исправить проблему соответствующим образом. Так что нынешняя версия поддерживает идею логической константы.

    Recommended practice: The non-member get() idiom

    Неясное поведение возможности модифицировать не<const>обернутый объект из постоянной обертки (как было поддержано предыдущими версиями<value_initialized>) можно избежать, если доступ к обернутому объекту всегда выполняется с идиомой<get()>:

    value_initialized<int> x ;
    get(x) = 1 ; // OK

    value_initialized<int const> cx ;
    get(x) = 1 ; // ERROR: Cannot modify a const object

    value_initialized<int> const x_c ;
    get(x_c) = 1 ; // ERROR: Cannot modify a const object

    value_initialized<int const> const cx_c ;
    get(cx_c) = 1 ; // ERROR: Cannot modify a const object

    template class initialized<T>

    namespace boost {

    template<class T>
    class initialized
    {
    public :
    initialized() : x() {}
    explicit initialized(T const & arg) : x(arg) {}
    operator T const &() const;
    operator T&();
    T const &data() const;
    T& data();
    void swap( initialized& );

    private :
    unspecified x ;
    } ;

    template<class T>
    T const& get ( initialized<T> const& x );

    template<class T>
    T& get ( initialized<T>& x );

    template<class T>
    void swap ( initialized<T>& lhs, initialized<T>& rhs );

    } // namespace boost
    The template class boost::initialized<T> supports both value-initialization and direct-initialization, so its interface is a superset of the interface of value_initialized<T>: Its default-constructor value-initializes the wrapped object just like the default-constructor of value_initialized<T>, but boost::initialized<T> also offers an extra explicit constructor, which direct-initializes the wrapped object by the specified value.

    <initialized<T>>особенно полезно, когда обернутый объект должен быть либо инициализирован, либо непосредственно инициализирован, в зависимости от условий выполнения. Например,<initialized<T>>может содержать значение элемента данных, которое может быть инициализировано некоторыми конструкторами и непосредственно инициализировано другими. С другой стороны, если заранее известно, что объектвсегдадолжен быть инициализирован,<value_initialized<T>>может быть предпочтительным. И если объект всегда должен быть непосредственно инициализирован, ни одна из двух оберток действительно не должна использоваться.

    initialized_value

    namespace boost {
    class initialized_value_t
    {
      public :
        template <class T> operator T() const ;
    };
    initialized_value_t const initialized_value = {} ;
    } // namespace boost
    
    initialized_value provides a convenient way to get an initialized value: its conversion operator provides an appropriate value-initialized object for any CopyConstructible type. Suppose you need to have an initialized variable of type T. You could do it as follows:
      T var = T();
    
    But as mentioned before, this form suffers from various compiler issues. The template value_initialized offers a workaround:
      T var = get( value_initialized<T>() );
    
    Unfortunately both forms repeat the type name, which is rather short now (T), but could of course be more like Namespace::Template<Arg>::Type. Instead, one could use initialized_value as follows:
      T var = initialized_value ;
    

    References

    [1] Bjarne Stroustrup, Gabriel Dos Reis, and J. Stephen Adamczyk wrote various papers, proposing to extend the support for brace-enclosed initializer lists in the next version of C++. This would allow a variable var of any DefaultConstructible type T to be value-initialized by doing T var = {}. The papers are listed at Bjarne's web page, My C++ Standards committee papers
    [2] Scott Meyers, Effective C++, Third Edition, item 6, Explicitly disallow the use of compiler-generated functions you do not want, Scott Meyers: Books and CDs
    [3] The C++ Standard, Second edition (2003), ISO/IEC 14882:2003
    [4] POD stands for "Plain Old Data"

    Acknowledgements

    value_initialized was developed by Fernando Cacciola, with help and suggestions from David Abrahams and Darin Adler.
    Special thanks to Björn Karlsson who carefully edited and completed this documentation.

    Value_initialized была перезапущена Фернандо Каччиолой (Fernando Cacciola) и Нильсом Деккером (Niels Dekker) для релиза Boost версии 1.35 (2008), предлагая обходной путь к различным проблемам компилятора.

    <boost::initialized>был очень вдохновлен отзывами Эдварда Динера и Джеффри Хеллрунга.

    Начальное значение было написано Нильсом Деккером и добавлено к версии 1.36 (2008) Boost.

    РазработанныйФернандо Каччиолой, последнюю версию этого файла можно найти наwww.boost.org.


    Пересмотрено 30 мая 2010 года

    © Авторское право Fernando Cacciola, 2002 - 2010.

    Распространяется в соответствии с Лицензией на программное обеспечение Boost, версия 1.0. См.www.boost.org/LICENSE_1_0.txt



    Статья value_initialized раздела может быть полезна для разработчиков на c++ и boost.




    Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



    :: Главная :: ::


    реклама


    ©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
    Top.Mail.Ru

    Время компиляции файла: 2024-08-30 11:47:00
    2025-05-19 17:15:47/0.033324956893921/1