2015-03-13 2 views
2

Вот простой пример:Одна переменная декларация создает несколько экземпляров

class A { 
public: 
    A() { 
    printf("%p C1\n", this); 
    } 
    A(const char* p) { 
    printf("%p C2\n", this); 
    } 
}; 

int main(int argc, char *argv[]) { 
    A a; 
    a = "abc"; 
} 

В коде, хотя A объявлен только один раз, есть два экземпляра A получения созданные. Конструктор вызывается дважды. Я мог бы воспроизвести это на VS 2013, а также на gnu C++.

Удовлетворение является ли это ошибкой или частью спецификации.

+0

Вы можете избежать временной путем определения 'А оператор :: = (Const символ *)' (или лучше 'A :: operator = (std :: string const &)'). – Walter

+0

'Удивление, если это поведение является ошибкой. Вы использовали два компилятора, используемые тысячами людей и компаний по всему миру, и получили те же результаты от такого тривиального кода. Учитывая, что это может быть ошибка? – PaulMcKenzie

+0

@MatthewMoss Мой вопрос в конце моего комментария был действительно предназначен для саркастичности. Программа представляет собой игрушечную программу, g ++ и Visual Studio используются тысячами людей. Если бы это было ошибкой, это было бы сообщено по всей сети (добавьте, что вероятность того, что два независимых поставщика компилятора будут производить ту же ошибку с такой смехотворно простой программой). – PaulMcKenzie

ответ

4

Потому что вы не отключили оператор присваивания автоматически сгенерированный или конструктор копирования, ваш класс на самом деле выглядит это компилятор:

class A { 
public: 
    A() { 
    printf("%p C1\n", this); 
    } 
    A(const A& rhs) { } 
    A(const char* p) { 
    printf("%p C2\n", this); 
    } 
    A& operator=(const A& rhs) { return *this; } 
}; 

Так a = "abc" интерпретируется как a.operator=(A("abc"))

Это ожидающей const A& как аргумент operator=, который он может построить, поскольку вы предоставили конструктор A(const char*).

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

class A { 
public: 
    A() { 
    printf("%p C1\n", this); 
    } 
    explicit A(const char* p) { 
    printf("%p C2\n", this); 
    } 
}; 

Тогда это должно не компилироваться:

int main(int argc, char *argv[]) { 
    A a; 
    a = "abc"; 
} 

Если вы явно не построить: a = A("abc");

+0

Хорошая точка в 'explicit'. –

+0

Спасибо, @ChristianHackl. Хорошая практика заключается в том, чтобы сделать конструкторы преобразования «явными», если вы не знаете о том, что делаете. И, может быть, даже не тогда ... –

6

Это часть спецификации. Когда вы сделаете это:

a = "abc"; 

временный A объект создается Сформируйте "abc" выражение на RHS, используя A(const char* p) конструктор. Это используется для присвоения значения a.

Если вы сделали это вместо

A a = "abc"; 

вы бы видеть только один вызов конструктора.

+3

Для полноты вы можете перегрузить 'operator = (const char *)', чтобы выполнить назначение, обеспечивая лучшее совпадение, чем создание временного объекта. – chris

Смежные вопросы