Инициализация объекта - PullRequest
       9

Инициализация объекта

2 голосов
/ 16 ноября 2010

Я работаю над встроенным программным обеспечением. Ранее мы не использовали слишком много функций C ++, поэтому мы используем memset (this, 0, sizeof (child)) для инициализации (обнуления) объекта. Однако сейчас это не работает, так как мы используем виртуальные функции. Очевидно, это уничтожило бы виртуальный / виртуальный указатель.

Итак, мой вопрос: Как быстро и удобно инициализировать объект?

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

Большое спасибо.

Ответы [ 5 ]

4 голосов
/ 16 ноября 2010

Использование размещения new, безусловно, является опцией, позволяющей избежать обнуления памяти.Используйте delete [] для удаления памяти.

struct base{virtual ~base(){}};
struct derived : base{};

int main() 
{
   char *p = new char[sizeof(derived)];
   memset(p, 0, sizeof(derived));
   derived *pd = new (p) derived;
}
4 голосов
/ 16 ноября 2010

Вы просите использовать возможности C ++, но не хотите снижения производительности при инициализации для каждого члена.Во-первых, я бы спросил себя, действительно ли это тот хит, о котором вы говорите.Существует множество более узких мест, которые вы можете искать, чем установка члена в 0.

Но если вы хотите использовать функции C ++ и все еще хотите скорость memset(), тогда я предлагаю вам поместить данныеэтот класс в другом классе, инициализируйте его значением 0 и передайте его классу, который будет использовать его по ссылке.

3 голосов
/ 17 ноября 2010

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Это дешевый и грязный хак, не очень C ++, и ненавистники будут его ненавидеть. Но эй. Если ты должен делать то, что должен, и то, что тебе нужно, это POD, то это сработает.

Если вы можете взять элементы данных, которые вы хотите memset, и поместить их в свой собственный POD, вы можете настроить этот POD. Для остроумия (POD, о котором идет речь, это структура BucketOBits):

ПРИМЕЧАНИЕ. Важно, чтобы используемый здесь тип данных был POD (Plain Old Data). Подробнее о том, что это значит, см. эту запись FAQ .

#include <cstdlib>
#include <cstring>


class Interface
{
public:
    virtual void do_it() const = 0;
    virtual ~Interface() {};
};

class Object : public Interface
{
public:
    Object();
    void do_it() const {};
private:
    struct BucketOBits
    {
        int int_a_;
        int int_b_;
        int int_c_;
    } bucket_;
};

Object::Object() 
{   
    memset(&bucket_, 0, sizeof(bucket_));
};

int main()
{
    Interface* ifc = new Object;
}

Еще лучше, вы можете использовать тот факт, что инициализация значений для целочисленных типов означает нулевую инициализацию, и полностью избавиться от memset, в то же время может даже сделать ваш код немного быстрее, чем если бы вы использовали memset. Используйте конструкцию по умолчанию для BucketOBits в инициализации конструктора:

Object::Object() : bucket_()
{   
};

EDIT2:

Если у базовых и производных классов есть члены-данные, которые нуждаются в нулевой инициализации, вы все равно можете использовать этот метод, передав каждому классу свой собственный BucketOBits. Показательный пример:

#include <cstdlib>
#include <cstring>


class Interface
{
public:
    virtual void do_it() const = 0;
    Interface();
    virtual ~Interface() {};
private:
    struct BucketOBits
    {
        unsigned base_int_a_;
        unsigned base_int_b_;
        long base_int_c_;
    } bucket_
};

class Object : public Interface
{
public:
    Object();
    void do_it() const {};
private:
    struct BucketOBits
    {
        int int_a_;
        int int_b_;
        int int_c_;
    } bucket_;
};

Interface::Interface() : bucket_() 
{
}

Object::Object() : bucket_()
{   
}

int main()
{
    Interface* ifc = new Object;
}
2 голосов
/ 16 ноября 2010

Во-первых, вы не можете избежать использования конструктора, потому что он будет вызываться автоматически при создании объекта.Если вы сами не определяете конструктор, компилятор определит его для вас.К тому времени, когда вы вызываете memset(this), что, кстати, никогда не следует делать, конструктор уже был вызван.

Во-вторых, в C ++ инициализация и присваивание не совсем одно и то же.Инициализация на самом деле быстрее, поэтому вам следует инициализировать элементы данных в списке инициализации конструктора, а не присваивать им значения в теле конструктора.

Короче, я бы посоветовал вам не бороться сязык.

1 голос
/ 16 ноября 2010

какой-нибудь трюк, чтобы использовать memset, не разрушая vtable?(независимый от компилятора способ)

Нет способа обойти эту независимую платформу.
Причина в том, что vtable не размещен по определенному адресу, но может быть в началеобъект или сразу после последнего члена данных.Так что это не переносимо, чтобы начать вычислять адреса и перепрыгивать через него.Кроме того, размер указателя зависит от архитектуры и т. Д.
Для множественного наследования это ухудшается.
Вы должны использовать либо список инициализации (не присваивание в конструкторе), либо размещение нового в качестве ответа Chubsdad.

Если мне нужно только обнулить все элементы данных, каким-либо способом избежать назначения член-член в конструкторе потомка без использования memset ()?

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

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