Создание и хранение строки в объединении внутри структуры в векторе C ++ 14 (Unrestricted Union) - PullRequest
0 голосов
/ 13 сентября 2018

Может кто-нибудь объяснить, как назначить и вставить строку (в объединении внутри структуры) в вектор?Это возможно?Вектор пытается получить доступ к недопустимой памяти?

#include <iostream>
#include <string>
#include <vector>

using namespace std;

typedef struct {
            int height;
            int width;
        } Page;

typedef struct varstruct{
            int test;
            union uni{
                Page page;
                int intVar;
                string stringVar;
                uni(){
                 new (&stringVar) std::string();
                }
                ~uni(){}
            } VarUnion;
            varstruct(){}
            ~varstruct(){}
        } VariableDataStruct;

vector<VariableDataStruct> List;

int main()
{
    VariableDataStruct structeg;
    structeg.test = 1;
    structeg.VarUnion.stringVar = "Test";
    List.push_back(structeg);
    cout<<structeg.VarUnion.stringVar<<endl;
    structeg.VarUnion.stringVar.~basic_string();
    return 0;
}

Код отлично работает при отсутствии "List.push_back (structeg);"заявление.При добавлении этого утверждения выдает следующие ошибки :

In file included from /usr/include/c++/4.8.3/x86_64-redhat-linux/bits/c++allocator.h:33:0,
                 from /usr/include/c++/4.8.3/bits/allocator.h:46,
                 from /usr/include/c++/4.8.3/string:41,
                 from /usr/include/c++/4.8.3/bits/locale_classes.h:40,
                 from /usr/include/c++/4.8.3/bits/ios_base.h:41,
                 from /usr/include/c++/4.8.3/ios:42,
                 from /usr/include/c++/4.8.3/ostream:38,
                 from /usr/include/c++/4.8.3/iostream:39,
                 from unionstring2.cc:1:
/usr/include/c++/4.8.3/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = varstruct; _Args = {const varstruct&}; _Tp = varstruct]’:
/usr/include/c++/4.8.3/bits/alloc_traits.h:254:4:   required from ‘static typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = varstruct; _Args = {const varstruct&}; _Alloc = std::allocator<varstruct>; typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type = void]’
/usr/include/c++/4.8.3/bits/alloc_traits.h:393:57:   required from ‘static decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = varstruct; _Args = {const varstruct&}; _Alloc = std::allocator<varstruct>; decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = <type error>]’
/usr/include/c++/4.8.3/bits/stl_vector.h:906:34:   required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = varstruct; _Alloc = std::allocator<varstruct>; std::vector<_Tp, _Alloc>::value_type = varstruct]’
unionstring2.cc:34:28:   required from here
/usr/include/c++/4.8.3/ext/new_allocator.h:120:4: error: use of deleted function ‘varstruct::varstruct(const varstruct&)’
  { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
    ^
unionstring2.cc:12:16: note: ‘varstruct::varstruct(const varstruct&)’ is implicitly deleted because the default definition would be ill-formed:
 typedef struct varstruct{
                ^
unionstring2.cc:12:16: error: use of deleted function ‘varstruct::uni::uni(const varstruct::uni&)’
unionstring2.cc:14:19: note: ‘varstruct::uni::uni(const varstruct::uni&)’ is implicitly deleted because the default definition would be ill-formed:
             union uni{
                   ^
unionstring2.cc:17:10: error: union member ‘varstruct::uni::stringVar’ with non-trivial ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
   string stringVar;
          ^
In file included from /usr/include/c++/4.8.3/vector:62:0,
                 from unionstring2.cc:3:
/usr/include/c++/4.8.3/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = varstruct; _Args = {varstruct}]’:
/usr/include/c++/4.8.3/bits/stl_uninitialized.h:75:53:   required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<varstruct*>; _ForwardIterator = varstruct*; bool _TrivialValueTypes = false]’
/usr/include/c++/4.8.3/bits/stl_uninitialized.h:117:41:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<varstruct*>; _ForwardIterator = varstruct*]’
/usr/include/c++/4.8.3/bits/stl_uninitialized.h:258:63:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<varstruct*>; _ForwardIterator = varstruct*; _Tp = varstruct]’
/usr/include/c++/4.8.3/bits/stl_uninitialized.h:281:69:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = varstruct*; _ForwardIterator = varstruct*; _Allocator = std::allocator<varstruct>]’
/usr/include/c++/4.8.3/bits/vector.tcc:415:43:   required from ‘void std::vector<_Tp, _Alloc>::_M_emplace_back_aux(_Args&& ...) [with _Args = {const varstruct&}; _Tp = varstruct; _Alloc = std::allocator<varstruct>]’
/usr/include/c++/4.8.3/bits/stl_vector.h:911:27:   required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = varstruct; _Alloc = std::allocator<varstruct>; std::vector<_Tp, _Alloc>::value_type = varstruct]’
unionstring2.cc:34:28:   required from here
/usr/include/c++/4.8.3/bits/stl_construct.h:75:7: error: use of deleted function ‘varstruct::varstruct(const varstruct&)’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }

Есть ли альтернатива?

1 Ответ

0 голосов
/ 13 сентября 2018

Один из членов вашего союза string, согласно ссылке

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

, поэтому вы не можете скомпилировать, потому что во время вызова vector::push_back вызывается конструктор копирования uni, но эта функция удаляется. Если вы хотите скомпилировать свой код, вам нужно добавить конструктор копирования:

uni(const uni& u) {
                new (&stringVar) std::string{u.stringVar};
            }

тогда ваш код компилируется и даже работает, но не рекомендуется использовать объединение с нетривиальными типами. Вы должны добавить type член к вашей структуре, чтобы контролировать, какой тип вашего объединения активен. Затем вы можете удалить в деструкторе нужный член (вызвать деструктор для нетривиальных типов). Хороший пример представлен в книге Бьярна Страуструпа Язык программирования C ++ , глава Анонимные союзы .

Измененная версия (это не полный код, только IDEA) вашего кода с type членом в структуре:

enum TYPE {INT,STR,PAGE};

typedef struct varstruct{
        int test;

        union {
            Page page;
            int intVar;
            string stringVar;
        };

        void setPage (Page p) {
            if (type == STR)
                stringVar.~string();
            page = p; 
            type = PAGE;
        }

        void setInt (int i) {
            if (type == STR)
              stringVar.~string();
            intVar = i; 
            type = INT;
        }

        void setString (string s) {
            if (type == STR)
                stringVar = s;
            else 
                new (&stringVar) std::string{s};
            type = STR;
        }

        TYPE type = INT;

        varstruct (const varstruct& v) {
            if (v.type == STR)
                new (&stringVar) std::string{v.stringVar};
            else if (v.type == INT)
                intVar = v.intVar;
            else if (v.type == PAGE)
                page = v.page;
            type = v.type;
        }


        varstruct(){}
        ~varstruct(){
            if (type == STR)
                stringVar.~string();
        }
    } VariableDataStruct;

и код в основном:

VariableDataStruct structeg;
structeg.test = 1;
structeg.setString("Test");
List.push_back(structeg);
cout<<structeg.stringVar<<endl;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...