Определение деструктора базового класса приводит к сбою std :: map :: emplace - PullRequest
0 голосов
/ 06 марта 2020

Когда я пытаюсь вставить объект, который имеет unique_ptr и деструктор, в карту, я получаю ошибку компилятора, показанную ниже. Тем не менее, когда объект не имеет деструктора, операция размещения работает нормально. Что здесь происходит?

Как я могу добавить объект, у которого есть unique_ptr и деструктор, определенный в карту?

#include <map>
#include <iostream>
#include <string>

struct A {
    std::string name;
    std::unique_ptr<int> p;
    virtual ~A(){};  // comment out this line
    A(std::string n) : name(n) { }
};
int main()
{
    std::map<int, A> m;
    m.emplace(1, A("Name"));
    return 0;
}

Я использую Apple Clang версии 11.0.0 на OSX

Ошибка компилятора

In file included from main.cpp:1:
In file included from /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/map:480:
In file included from /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/__tree:16:
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:1826:31: error: no matching constructor for initialization of 'std::__1::pair<const int, B>'
            ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
                              ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:1718:18: note: in instantiation of function template specialization
      'std::__1::allocator<std::__1::__tree_node<std::__1::__value_type<int, B>, void *> >::construct<std::__1::pair<const int, B>, int, B>' requested here
            {__a.construct(__p, _VSTD::forward<_Args>(__args)...);}
                 ^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:1561:14: note: in instantiation of function template specialization
      'std::__1::allocator_traits<std::__1::allocator<std::__1::__tree_node<std::__1::__value_type<int, B>, void *> > >::__construct<std::__1::pair<const int, B>,
      int, B>' requested here
            {__construct(__has_construct<allocator_type, _Tp*, _Args...>(),
             ^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/__tree:2212:20: note: in instantiation of function template specialization
      'std::__1::allocator_traits<std::__1::allocator<std::__1::__tree_node<std::__1::__value_type<int, B>, void *> > >::construct<std::__1::pair<const int, B>,
      int, B>' requested here
    __node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__value_), _VSTD::forward<_Args>(__args)...);
                   ^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/__tree:2157:29: note: in instantiation of function template specialization
      'std::__1::__tree<std::__1::__value_type<int, B>, std::__1::__map_value_compare<int, std::__1::__value_type<int, B>, std::__1::less<int>, true>,
      std::__1::allocator<std::__1::__value_type<int, B> > >::__construct_node<int, B>' requested here
        __node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
                            ^

... [similar error messages come here]

main.cpp:19:11: note: in instantiation of function template specialization 'std::__1::map<int, B, std::__1::less<int>, std::__1::allocator<std::__1::pair<const
      int, B> > >::emplace<int, B>' requested here
        m.emplace(1, B("Name"));
      ^

1 Ответ

3 голосов
/ 06 марта 2020

std::map::emplace позволяет создать объект на месте, передав constructor's arguments, и вам не нужно копировать / перемещать. Как упоминается в одном из комментариев, что из-за предоставленного пользователем distructor, компилятор не создает неявно конструктор перемещения. Но я добавил перемещение, потому что иначе оно бесполезно в реальных условиях.

Из-за этого вам нужно создать объект на месте.

Используя следующий код.

#include <iostream>

#include <map>
#include <memory>

struct A {
    std::string name;
    std::unique_ptr<int> p;
    ~A(){}
    A(std::string n) : name(n) { }
    A(A&& other): name(std::move(other.name)), p(std::move(other.p)){}
};

int main(int , char *[]){

std::map<int, A> m;
    m.emplace(1, "Name");

    for(const auto& e: m)
        cout<< e.first<< ", "<< e.second.name<<'\n';
}

вывод: 1, Name

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