Вызывает ли конструктор пустого класса какую-то память? - PullRequest
9 голосов
/ 07 января 2010

Предположим, у меня есть класс, подобный

class Empty{
    Empty(int a){ cout << a; }
}

А потом я вызываю его, используя

int main(){
    Empty(2);
    return 0;
}

Приведет ли это к выделению памяти в стеке для создания «пустого» объекта? Очевидно, что аргументы должны быть помещены в стек, но я не хочу нести никаких дополнительных затрат. В основном я использую конструктор в качестве статического члена.

Причина, по которой я хочу это сделать, заключается в шаблонах. Фактический код выглядит как

template <int which>
class FuncName{
    template <class T>
    FuncName(const T &value){
        if(which == 1){
            // specific behavior
        }else if(which == 2){
            // other specific behavior
        }
    }
};

, который позволяет мне написать что-то вроде

int main(){
    int a = 1;
    FuncName<1>(a);
}

так что я могу специализироваться на одном параметре шаблона, не указывая тип T. Кроме того, я надеюсь, что компилятор оптимизирует другие ветви внутри конструктора. Если кто-нибудь знает, правда ли это или как проверить, это будет с благодарностью. Я также предположил, что добавление шаблонов в ситуацию не меняет проблему «пустого класса» сверху, это верно?

Ответы [ 3 ]

17 голосов
/ 07 января 2010

Цитирование Страуструпа:

Почему размер пустого класса не равен нулю?Чтобы гарантировать, что адреса двух разных объектов будут разными.По той же причине «new» всегда возвращает указатели на различные объекты.Рассмотрим:

class Empty { };

void f()
{
    Empty a, b;
    if (&a == &b) cout << "impossible: report error to compiler supplier";

    Empty* p1 = new Empty;
    Empty* p2 = new Empty;
    if (p1 == p2) cout << "impossible: report error to compiler supplier";
}   

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

struct X : Empty {
    int a;
    // ...
};

void f(X* p)
{
    void* p1 = p;
    void* p2 = &p->a;
    if (p1 == p2) cout << "nice: good optimizer";
}

Эта оптимизация безопасна и может быть наиболее полезной,Это позволяет программисту использовать пустые классы для представления очень простых концепций без дополнительных затрат.Некоторые текущие компиляторы предоставляют эту «пустую оптимизацию базового класса».

2 голосов
/ 07 января 2010

Попробуйте и посмотрите. Многие компиляторы удаляют такие временные объекты, когда их просят оптимизировать их вывод.

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

void empty1 ( int x )
{
    using namespace std;

    int a;
    Empty e1 ( x );
    int b;

    cout << endl;
    cout << "empty1" << endl;
    cout << hex << int ( &x ) << " " << dec << ( &x - &a ) << endl;
    cout << hex << int ( &a ) << " " << dec << ( &a - &b ) << endl;
}

, а затем попробуйте запустить эту функцию по сравнению с empty8 функцией с восьмью созданными тарами. С g ++ на x86, если вы берете адрес любого из пустых мест, вы получаете место между x и a в стеке, следовательно, включая x в вывод. Вы не можете предполагать, что хранилище для объектов будет в том же порядке, в каком они объявлены в исходном коде.

2 голосов
/ 07 января 2010

Может, а может и нет, в зависимости от обстоятельств. Если вы говорите:

Empty e;
Empty * ep = & e;

тогда, очевидно, вещи должны быть распределены.

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