просмотреть функции по умолчанию, сгенерированные компилятором?

Там какой-либо путь состоит в том, чтобы просмотреть функции по умолчанию (например, значение по умолчанию копирует конструктора, оператор присваивания по умолчанию), сгенерированный компилятором, таким как VC ++ 2008 для класса, который не определяет их?

8
задан Southsouth 24 January 2010 в 22:37
поделиться

5 ответов

с компилятором Clang , вы можете увидеть их, передавая аргумент -AST -AST . Clang все еще находится на этапе развития, но вы уже можете использовать его для этих вещей:

[js@HOST2 cpp]$ cat main1.cpp
struct A { };
[js@HOST2 cpp]$ clang++ -cc1 -ast-dump main1.cpp
typedef char *__builtin_va_list;
struct A {
public:
    struct A;
    inline A();
    inline A(struct A const &);
    inline struct A &operator=(struct A const &);
    inline void ~A();
};
[js@HOST2 cpp]$

Я надеюсь, что это то, что вы просили. Давайте изменим код и посмотрите еще раз.

[js@HOST2 cpp]$ cat main1.cpp
struct M { M(M&); };
struct A { M m; };
[js@HOST2 cpp]$ clang++ -cc1 -ast-dump main1.cpp
typedef char *__builtin_va_list;
struct M {
public:
    struct M;
    M(struct M &);
    inline struct M &operator=(struct M const &);
    inline void ~M();
};
struct A {
public:
    struct A;
    struct M m;
    inline A();
    inline A(struct A &);
    inline struct A &operator=(struct A const &);
    inline void ~A();
};
[js@HOST2 cpp]$

Обратите внимание, как неявно объявленная конструктор копирования теперь имеет ссылочный параметр , потому что один из его участников тоже имеет (член m ), а это M не имеет заявленного конструктора по умолчанию.

Для получения сгенерированного кода вы можете позволить ему выделять промежуточный язык виртуальной машины. Давайте посмотрим на сгенерированный код для этого:

struct A { virtual void f(); int a; };
A f() { A a; a = A(); return a; } // using def-ctor, assignment and copy-ctor

[js@HOST2 cpp]$ clang++ -cc1 -O1 -emit-llvm -o - main1.cpp | c++filt
[ snippet ]
define linkonce_odr void @A::A()(%struct.A* nocapture %this) nounwind align 2 {
entry:
  %0 = getelementptr inbounds %struct.A* %this, i32 0, i32 0 ; <i8***> [#uses=1]
  store i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i32 0, i32 2), i8*** %0
  ret void
}

define linkonce_odr %struct.A* @A::operator=(A const&)(%struct.A* %this, 
  %struct.A* nocapture) nounwind align 2 {
entry:
  %tmp = getelementptr inbounds %struct.A* %this, i32 0, i32 1 ; <i32*> [#uses=1]
  %tmp2 = getelementptr inbounds %struct.A* %0, i32 0, i32 1 ; <i32*> [#uses=1]
  %tmp3 = load i32* %tmp2                         ; <i32> [#uses=1]
  store i32 %tmp3, i32* %tmp
  ret %struct.A* %this
}

define linkonce_odr void @A::A(A const&)(%struct.A* nocapture %this, %struct.A* nocapture) 
  nounwind align 2 {
entry:
  %tmp = getelementptr inbounds %struct.A* %this, i32 0, i32 1 ; <i32*> [#uses=1]
  %tmp2 = getelementptr inbounds %struct.A* %0, i32 0, i32 1 ; <i32*> [#uses=1]
  %tmp3 = load i32* %tmp2                         ; <i32> [#uses=1]
  store i32 %tmp3, i32* %tmp
  %1 = getelementptr inbounds %struct.A* %this, i32 0, i32 0 ; <i8***> [#uses=1]
  store i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i32 0, i32 2), i8*** %1
  ret void
}

Теперь я не понимаю, что промежуточный язык (который определяется в llvm.org ). Но вы можете перевести все этот код в C, используя компилятор LLVM:

[js@HOST2 cpp]$ clang++ -cc1 -O1 -emit-llvm -o - main1.cpp | llc -march=c -o - | c++filt
[snippet]
void A::A()(struct l_struct.A *llvm_cbe_this) {
  *((&llvm_cbe_this->field0)) = ((&_ZTV1A.array[((signed int )2u)]));
  return;
}


struct l_struct.A *A::operator=(A const&)(struct l_struct.A *llvm_cbe_this, struct l_struct.A
  *llvm_cbe_tmp__1) {
  unsigned int llvm_cbe_tmp3;

  llvm_cbe_tmp3 = *((&llvm_cbe_tmp__1->field1));
  *((&llvm_cbe_this->field1)) = llvm_cbe_tmp3;
  return llvm_cbe_this;
}


void A::A(A const&)(struct l_struct.A *llvm_cbe_this, struct l_struct.A *llvm_cbe_tmp__2) {
  unsigned int llvm_cbe_tmp3;

  llvm_cbe_tmp3 = *((&llvm_cbe_tmp__2->field1));
  *((&llvm_cbe_this->field1)) = llvm_cbe_tmp3;
  *((&llvm_cbe_this->field0)) = ((&_ZTV1A.array[((signed int )2u)]));
  return;
}

TADA! Обратите внимание, как он устанавливает указатель виртуальной таблицы в конструкторе копирования и конструктору по умолчанию. Надеюсь это поможет.

11
ответ дан 5 December 2019 в 08:52
поделиться

Вы можете проследить код с отладчиком, чтобы увидеть, что происходит. Например:

#include <string>

struct A {
    int a[100];
    char c;
    std::string s;
};

int main() {
    A a;
    A b(a);
}

Установите точку останова при построении «B» конструктором копирования. Выход из ассемблера в этой точке в отладчике VC ++ 6:

12:       A b(a);
00401195   lea         eax,[ebp-1B0h]
0040119B   push        eax
0040119C   lea         ecx,[ebp-354h]
004011A2   call        @ILT+140(A::A) (00401091) 

Последний - это вызов конструктора копирования. Вы также можете проследить это, если вы хотите больше деталей.

Однако, если ваш вопрос: «Как я могу увидеть код C ++ для Copy Contrector et al», ответ - вы не можете, потому что нет ни одного - компилятор генерирует ассемблер или машинный код (в зависимости от Ваш компилятор) для них код не C ++.

7
ответ дан 5 December 2019 в 08:52
поделиться

Инструмент просмотра объектов (например, objdump или dumpbin) может разобрать для Вас файлы выходных объектов. Затем Вы можете осмотреться и посмотреть, какие инструкции выдаются для интересующих Вас функций/методов.

0
ответ дан 5 December 2019 в 08:52
поделиться

Вы уверены, что вам нужно просмотреть эту функцию?

По умолчанию компилятор создает их, вызывая Copy Constructor или оператор назначения на каждой переменме участника.

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

class aClass
{
  int one;
  int *ptwo;
};

Конструктор копирования по умолчанию только копирует данные A и указатель б. Однако он не копирует данные, указанные на B. Если вы используете этот класс, например

aClass a, b;
a.ptwo = new int;
a.one = 1;
*(a.ptwo) = 2;

b = a;

*(b.ptwo) = 1;  
//a.ptwo now points to an integer with the value of 1

, если вы хотите, чтобы этот класс копировать значение PTWO вместо указателя, вам понадобится ваша собственная функция оператора назначения копирования. Если вы заинтересованы в более подробных деталях, какие функции по умолчанию делают и что нет, вы посмотрите в книгу «Эффективные C ++».
У него есть целая глава на этом веществе, что объясняет, что делать функции по умолчанию классов, не делают, то, что они должны делать, когда писать свои собственные. Я уверен, что вы можете получить цифровую версию в Интернете, если вы просто хотите знать об этой функциональности.

-1
ответ дан 5 December 2019 в 08:52
поделиться

Сгенерированные компиляторы методы абстрактны, они не существуют в исходном коде.
Посмотрите на пример ниже, я стараюсь объяснить, что - четыре метода методов компилятора, должны делать на уровне исходного кода. От этого вы должны быть в состоянии экстраполировать любой нормальный класс.

Если у вас есть такой класс:

class X: public Base
{
    int*   a;
    double b;
    Y      c;
};

, то компилятор генерирует эквивалент следующего:

X::X() // Default constructor
    :Base() Calls the base class default constructor
    //,a    pointers are POD no default initialization
    //,b    double   are POD no default initialization
    ,c()    //Call default constructor on each non POD member
{}

X::~X() // Default destructor
{}
// Destructor for each non POD member in reverse order
~c()       calls the destructor of the class type
//~b       double are POD no destructor
//~a       pointers are POD no destructor
~Base()    // Calls the base class destructor

X::X(X const& copy)
    :Base(copy)    // calls the base class copy constructor
    // Copies each member using its copy constructor
    ,a(copy.a)     // Pointers copied  (Note just the pointer is copied, not what it points at)
    ,b(copy.b)     // Double copied.
    ,c(copy.c)     // Uses copy constructor of the class type (must be accessible)
{}

X& X::operator=(X const& copy)
{
    Base::operator=(copy);  // Calls the base class assignment operator
    // Copies each member using the members assignment operator
    a = copy.a;    // Pointers copied  (Note just the pointer is copied, not what it points at)
    b = copy.b;    // Double copied
    c = copy.c;    // Uses assignment operator of the class type (must be accessible)

    return *this;
}
2
ответ дан 5 December 2019 в 08:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: