Почему этот вызов по ссылке создает новый экземпляр? - PullRequest
8 голосов
/ 20 сентября 2011

Я вызываю метод foo от const ref:

// method, which is being called
void foo(const Entity & ent);

// call
Entity* e = new Entity;
foo(e);    // wrong: missing * but compiles

Этот фрагмент кода не только компилируется, но и создает новый экземпляр Entity со значениями по умолчанию в области действия foo. Я ожидаю, что это не скомпилируется или, по крайней мере, вылетит.

Если я правильно наберу foo (foo(*e)), все работает, как подозревается, и я вижу правильные значения Entity в foo.

Я использую mingw, поставляемый с Qt 4.7.

Вот интерфейс Entity:

class Entity : public QObject
{
    Q_OBJECT

public:
    Entity (QObject* parent = NULL);

    long getId() const { return this->id; }
    void setId(const long id) { this->id = id; }

    QString getName() const { return this->name; }
    void setName(const QString & name) {this->name = name; }

private:
    QString name;
    long id;
};

Ответы [ 3 ]

15 голосов
/ 20 сентября 2011

[Отредактировано] У вас есть неявный конструктор преобразования (который также оказывается конструктором по умолчанию) из Entity* (через родительский QObject*) в Entity, и он используется для созданиявременный экземпляр для передачи.

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

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

2 голосов
/ 20 сентября 2011

На самом деле:

Entity* e = new Entity;
foo(e); //will call: 
-> foo ( Entity(e) ) ; //will call:
-> foo ( Entity((QObject*) e );

Вы создаете новый временный объект из указателя на объект (который также является указателем на объект QObject).

Он компилируется, потому что он действителен.

Как указал Марк, неявное преобразование из Entity * в Entity выполняется через конструктор, который принимает аргумент типа «указатель на QObject».Чтобы проверить это, измените наследование на private, вы должны получить ошибку компиляции.

Чтобы избежать таких ошибок в будущем, объявите конструкторы преобразования как explicit.

1 голос
/ 20 сентября 2011

Ваш конструктор Entity принимает аргумент QObject* и не помечается как explicit. Это означает, что Entity может быть сконструирован неявно из Entity*, что является довольно плохой новостью.

Далее, поскольку функция принимает ref-to- const, этот неявно созданный временный объект может быть связан с этим аргументом функции.

Отметить конструктор explicit.

...