Это передача по ссылке или по значению? - PullRequest
1 голос
/ 02 марта 2012

Допустим, у меня есть следующее:

class MyClass
{
    // ...
}

void doSomething (MyClass instance)
{
    // Is instance passed by reference or by value (copied)?
}

void main ()
{
    MyClass instance = MyClass();

    doSomething(instance);
}

В doSomething() передается instance по ссылке?Или класс дублируется в памяти?Или что-то еще?

Ответы [ 4 ]

5 голосов
/ 02 марта 2012

Это передается значением

void doSomething (MyClass instance)

Передается по ссылке

void doSomething (MyClass& instance)

Это передается по константной ссылке

void doSomething (const MyClass& instance)

Также MyClass не требуется по построению по заданию. Итак:

MyClass mc=MyClass();

фактически совпадает с:

MyClass mc; //no parens needed for default constructor (no args).

EDIT: Это передается с помощью константной ссылки на константную функцию, константная функция может быть вызвана на константном объекте, поскольку она гарантирует не изменять состояние объекта.

void doSomething (const MyClass& instance) const

В C ++ правильная практика считается хорошей практикой в ​​отличие от многих менее строгих языков.

см. Меня:

http://en.wikipedia.org/wiki/Const-correctness

http://www.gotw.ca/gotw/006.htm

1 голос
/ 02 марта 2012

дублируется в стеке для передачи в функцию. Это может быть очень дорого, если ваш класс достиг определенного количества байтов, поскольку каждая переменная экземпляра должна быть размещена в стеке. В этом случае класс не ведет себя иначе, чем обычная структура c.

Допустим, у вас 2 класса в классе (я полагаю, 32-битная система)

class A {
    int a;
    int b;
};

когда вы объявляете это в вашем main, указатель стека уменьшается на 8 байтов. если вы вызываете your_function (A), C должен также скопировать класс макета в стек, чтобы ваша_функция могла получить к нему доступ после вызова. это означает, что указатель стека снова уменьшается на 8 байтов, значение записывается из старых значений и вызывается функция.

с двумя переменными экземпляра, это не имеет большого значения. Но у вас есть класс, который содержит структуры и допустим 20 дюймов + виртуальный стол? чем я могу быть очень дорогой операцией. Если вы передадите указатель, указатель стека должен уменьшиться всего на 4 байта, скопировать в него адрес класса и вызвать функцию. намного дешевле, конечно.

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

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

1 голос
/ 02 марта 2012

Да, оно копируется.

При вызове doSomething вызывается конструктор копирования MyClass для создания нового экземпляра.

Этот экземпляр останется в области действия дляпродолжительность функции doSomething.Когда функция завершится, для этого экземпляра будет вызван деструктор MyClass.

(Обратите внимание, что если вы не написали конструктор копирования, он будет создан для вас по умолчанию.)

Таким образом, если вы добавите явный конструктор копирования и деструктор:

class MyClass
{
    public:
         MyClass()
         {
             std::cout << "MyClass constructor" << std::endl;
         }
         MyClass(const MyClass& other)
         {
               std::cout << "MyClass copy constructor" << std::endl;
         }
         MyClass::~MyClass()
         {
               std::cout << "MyClass destructor" << std::endl;
         }
}
void doSomething (MyClass instance)
{
    std::cout << "doSomething method";
}

void main ()
{
    MyClass instance = MyClass();
    std::cout << "invoking doSomething" << std::endl;
    doSomething(instance);
    std::cout << "returned from doSomething" << std::endl;
}

Это выведет следующее:

  • Конструктор MyClass
  • , вызывая doSomething
  • Конструктор копирования MyClass
  • Метод doSomething
  • Деструктор MyClass
  • , возвращаемый из doSomething
  • Деструктор MyClass
1 голос
/ 02 марта 2012

Если явно не указано, это не по ссылке. Это по значению.

Следующий прототип обозначает параметр, переданный по ссылке:

void doSomething (MyClass& instance)
{
    // Is instance passed by reference or by value (copied)?
    // In this case, by reference
}

Действительно, в вашем случае скорее всего создается новый объект. Я говорю, скорее всего, потому что, если наблюдаемое поведение одинаково, оно может и не быть. Но, теоретически, да, новый объект создан для использования внутри функции.

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

...