Присвоение значения, переданного по ссылке, переменной-члену (в C++)

Я пытаюсь понять область видимости в С++. Пожалуйста, обратите внимание на следующее:

class C
{
    int i_;
public:
    C() { i_ = 0;}
    C(int i) { i_ = i; }
    C(const C &c) {
        i_ = c.i_;
        cout << "C is being copied: " << i_ << endl;
    }
    int getI() { return i_; }
    ~C() {cout << "dstr: " << i_ << endl;}
};

class D
{
    C c_;
public:
    void setC(C &c) { c_ = c; }
    int getC_I() { return c_.getI(); }
};

void Test(D &d)
{
    C c(1);
    d.setC(c);
    //here c is going out of scope, surely it will be destroyed now?
}

int main()
{
    D d;
    Test(d); //this sets value of c_ to the local variable in Test. 
             //Surely this will be invalid when Test returns?
    int ii = d.getC_I();
    cout << ii << endl;
}

Запуск этой программы выводит:

dstr: 1
1
dstr: 1

Судя по всему, первый вызов деструктора происходит в Test, а второй — при завершении программы и уничтожении d.

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

Большое спасибо за вашу помощь.


person martin    schedule 25.06.2010    source источник


Ответы (3)


Ваш код в порядке сейчас. D::c_ имеет тип C, а не C &. Ваш SetC берет ссылку на C и присваивает значение, на которое ссылается эта ссылка, C::c_, поэтому у вас есть совершенно отдельный объект C с тем же значением. Поскольку вы создали d с автоматическим сроком хранения в main, он и c_, который является его частью, остаются в силе до тех пор, пока вы не выйдете из main.

person Jerry Coffin    schedule 25.06.2010

Где было скопировано?

Когда вы делаете c_ = c;Where was c copied?, вы вызываете operator= на c_, который копирует содержимое c в c_.

Если бы c_ было также ссылкой, ничего не было бы скопировано, и программа вызвала бы ошибку, которую вы ожидаете.

person sepp2k    schedule 25.06.2010

C копируется здесь:

void setC(C &c) { c_ = c; }

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

person Alex Korban    schedule 25.06.2010
comment
@Charles the Standard говорит, что объект класса можно скопировать двумя способами: путем инициализации [...] и путем присваивания (5.17). Концептуально эти две операции реализуются конструктором копирования (12.1) и оператором копирования (13.5.3). - person Johannes Schaub - litb; 26.06.2010
comment
@litb: Справедливо, я отзываю свой первоначальный комментарий и свой ответ. - person CB Bailey; 26.06.2010