2016-12-01 4 views
2

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

class Task { 
public: 
    Task() { 
     Handler::instance().add(this); 
    } 
    virtual void doSomething() = 0; 
}; 

class Handler { 
    std::vector<Task*> vec; 
    //yea yea, we are locking the option to use default constructor etc 
public: 
    static Handler& instance() { 
     static Handler handler; 
     return handler; 
    } 

    void add(Task* task) { 
     vec.push_back(task); 
    } 

    void handle() { 
     for (auto t : vec) { 
      t->doSomething(); 
     } 
    } 
}; 

template <class T, int SIZE> 
class MyTask : public Task { 
    T data[SIZE]; 
public: 
    virtual void doSomething() { 
     // actually do something 
    } 
}; 
//somewhere in the code: 
Handler::instance().handle(); 

теперь, мой класс что-то вроде

class A { 
    MyTask<bool, 128> myTask; 
public: 
    A(int i) {} 
}; 

на пути Я хотел сделать это, имея карту, где экземпляры A являются значениями

static std::map<int, A> map = { 
    {42, A(1948)}, 
    {88, A(-17)} 
}; 

Сначала прояснить что-то - этот код n чтобы работать в встроенной системе реального времени, поэтому мне не разрешено выделять память с использованием новых по нескольким причинам.

Моя проблема заключалась в том, что фактические объекты на карте не были явным образом созданы, и поэтому они не регистрировались в классе Handler (поэтому я не получил преимущества вызовов Handler :: handle) ,

Я пробовал найти хороший способ решить эту проблему, не делая что-то уродливое, как сначала создавая массив A, а только указывать на эти объекты на карте, например.

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

Однако, прочитав this answer (особенно в самом первом примере), мне показалось, что я ничего не могу извлечь из использования семантики перемещения.

Я попробовал это в любом случае (сог почему, черт возьми, не ...) и сделал что-то вроде этого: вместо

static std::map<int, A> map = { 
    {42, std::move(A(1948))}, 
    {88, std::move(A(-17))} 
}; 

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

Я попытался более подробно прочитать о std :: move, чтобы понять, что именно там произошло, но не смог найти ответ.

может кто-нибудь объяснить это? std :: move перемещает это указатель как-нибудь? или, возможно, это только вызвало регистрация произойдет правильно как-то и не было ничего реального делать с движущейся попыткой

благодаря

редактировать:

для дальнейшего уточнения, что я спрашиваю:

Я понимаю, что использование std :: move не способствовало тому, что там делается.

Но по какой-то причине он действительно получил мои объекты на карте, чтобы получить вызов doSomething() через обработчик. Я искал эту причину

на боковой ноте, поскольку она, вероятно, относится к другому вопросу - есть ли достойный способ инициализировать карту таким образом без накладных расходов на создание каждого объекта дважды?

+1

Этот вопрос по-прежнему не совсем ясен для меня. Ваш пример не имеет смысла - где эта 'std :: map' вступает в игру и как она каким-либо образом связана с« Handler »? Пожалуйста, создайте реальный [mcve] – AndyG

+0

, почему это имеет значение, где карта вступает в игру? и обработчик регистрирует созданные объекты задачи – user2717954

+0

Кроме того, если вам не разрешено выполнять выделение памяти, то вам, вероятно, не разрешено использовать использование 'std :: map' (если вы не предоставите ему специальный распределитель, который не нарушите ваши ограничения). – Hurkyl

ответ

1

У вашего вопроса есть намного больше, чем нужно, но я думаю, что понимаю коренной вопрос здесь.Конструктор std::map получает initialization_list, вы вызываете (5) from this list. Объекты копируются из initializer_list при повторении, а не перемещении, потому что копия initializer_list не копирует базовые объекты. То же самое касается других контейнеров std, вот пример с vector для демонстрации. (live link)

#include <vector> 
#include <iostream> 

struct Printer { 
    Printer() { std::cout << "default ctor\n"; } 
    Printer(const Printer&) { std::cout << "copy\n"; } 
    Printer(Printer&&) { std::cout << "move\n"; } 
}; 

int main() { 
    std::vector<Printer> v = {Printer{}}; 
} 

если вы используете {std::move(Printer{})} вы добавите еще один шаг в миксе, что компилятор не может легко оптимизировать прочь.

+0

Я вроде понимаю это, настоящий вопрос, почему он действительно решил мою проблему? – user2717954

+0

Если ваша проблема в том, что вы не можете использовать 'new', то это не так. map использует новый –

+0

Я могу использовать карту (да, я знаю, это звучит глупо, но это правила в моей компании) – user2717954