Что происходит, когда я изменяю конструктор копирования, чтобы сделать что-то странное, а затем передаю объект (этого класса) по значению функции? - PullRequest
1 голос
/ 31 января 2012
class C
{
public:
  C(C& c)
  {
    i = c.i;
    j = 100;
  }
  C() : i(0), j(0)
  {
  }

  int i, j;
};

C func(C c)
{
  return c;
}

int main()
{
  C c;
  c = func(c)
  // What is the value of j?
}

Выше представлен класс с необычным конструктором копирования. Вместо того, чтобы копировать i и j, он копирует i и назначает что-то еще j. Что происходит, когда я передаю объект класса функции?

Редактировать: Это просто сложно сделать в программе ...

Ответы [ 4 ]

8 голосов
/ 31 января 2012

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

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

Так что не пишите конструкторы копирования, которые делают странные вещи.(Иначе мы вам перезвоним auto_ptr)

1 голос
/ 31 января 2012

Это ваша ответственность за оснащение вашего класса конструктором копирования, так что выражение Foo x(y); приводит к объекту x, который семантически равен y.Никто не заставляет вас делать это каким-либо особым образом, и программа будет вести себя так, как вы , и скажете.

Рассмотрим этот упрощенный пример:

struct Foo
{
    int value;
    explicit Foo(int n) : value(n) { }
    Foo(Foo const & rhs) : value(rhs.n / 5 - 32) { } // tee-hee
};

Foo make_it_so() { return Foo(40); }

int main() { Foo k = make_it_so(); }

Теперь в зависимостив зависимости от того, исключен или нет конструктор копирования, k.value заканчивается либо 40, либо -24.Однако, поскольку вы написали конструктор копирования, вы, по сути, заявили, что считаете их семантически равными.

C ++ позволяет вам устанавливать правила игры, ноэто не защищает вас от попадания прямо в тюрьму.

(я знаю, что мой пример немного отличается от того, что вы задали в своем вопросе («передача аргументов»), но он предназначен для иллюстрации ваших обязанностей какавтор.)

0 голосов
/ 31 января 2012

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

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

0 голосов
/ 31 января 2012

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

Копирование-elision здесь не разрешено, так как аргумент, передаваемый в функцию, не является значением.Если бы это было значение r (например, func(C())), код не скомпилировался бы, поскольку временное не может быть связано с конструктором копирования, так как оно принимает ссылку в качестве аргумента, а не ссылку на const.Если это исправлено, copy-elision может наблюдаться для аргумента и возвращаемого значения.Таким образом, состояние c после присвоения может быть состоянием по умолчанию C.

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

...