Проблема понимания ссылок и копий в c ++ - PullRequest
3 голосов
/ 13 апреля 2011

Прежде всего, я прошу прощения, если я не использую правильные термины в названии моего вопроса.Это вполне возможно.Я начинаю изучать c ++, и я признаю, что мне действительно тяжело со ссылками и копиями.Что касается моего кода ниже, у меня есть следующие вопросы:

  1. В main.c - это аргумент, переданный функции Carrier.add () (* it), ссылка,или копию объекта плана, который я вставил в вектор, или что-то еще?

  2. Когда этот аргумент добавляется к вектору планов перевозчика (внутри класса перевозчика), добавляется ли копия?Как это работает, так как я не предоставил конструктор копирования и не сказал ему сделать копию?Я думаю, что он генерируется автоматически?

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

Вот мой код:

main.c

#include "stdafx.h"
#include <iostream>
#include "Plan.h"
#include "Carrier.h"

int _tmain(int argc, _TCHAR* argv[])
{

    std::vector<Plan> plans;

    for (int i = 0; i < 4; ++i) {
        Plan p(i);
        plans.push_back(p);
    }

    Carrier c(5);
    for(std::vector<Plan>::iterator it = plans.begin(); it != plans.end(); ++it) {
            //my question is about the line directly below this comment
        c.add(*it);
    }
    return 0;
}

Plan.h

#pragma once

class Plan
{
private:
    int id;
public:
    Plan(int id);
};

Plan.cpp

#include "Plan.h"

Plan::Plan(int i)
{
    id = i;
}

Carrier.h

#pragma once
#include <vector>
class Plan;
class Carrier
{
private:
    int id;
    std::vector<Plan> plans;
public:
    Carrier(int i);
    void add(Plan p);
};

Carrier.cpp

#include "Carrier.h"
#include "Plan.h"

Carrier::Carrier(int i) {
    id = i;
}

void Carrier::add(Plan p) {
    plans.push_back(p);
}

Ответы [ 5 ]

3 голосов
/ 13 апреля 2011

(1) Поскольку Carrier::add не принимает аргумент в качестве ссылки, ему передается копия.Чтобы получить ссылку, измените ее подпись на

void Carrier::add(Plan const &p);

(2) Когда вы делаете push_back, копия создается независимо от того, передаете ли вы Plan по ссылке или по значению / копии;это часть семантики std::vector (и всех других стандартных контейнеров).Конструктор копирования автоматически генерируется компилятором.

(3) Я не пользователь VC ++, но конструктор копирования, сгенерированный компилятором, эквивалентен

Plan::Plan(Plan const &other)
 : id(other.id)  // there's only one member,
                 // but other members would be treated the same
{}

.пустое тело, вы можете добавить оператор печати, указывающий, что вызывается конструктор копирования, но он не будет водонепроницаемым;в некоторых случаях C ++ может выполнять оптимизацию copy elision , что означает, что фактическое копирование пропускается.

2 голосов
/ 13 апреля 2011

Чтобы понять pass-by-value и pass-by-reference, вам нужно знать, что такое ссылки. References похожи на aliases в той же ячейке памяти.

Хотя приведенный ниже код не имеет ничего общего с вашим вопросом, я намеренно взял простой пример, чтобы продемонстрировать, что происходит.

#include<iostream>
void foo(int , int & ); //Declaration of foo

void foo(int copy, int &reference)
{
          copy++; // Updates the Local Variable Copy 
          reference++;  // Updates x
}

int main(){
    int x=10;
    int &reftox=x; // reference to x
    foo(x,reftox);
    std::cout << x;
}

Вывод будет 11. На остальные сомнения относительно вашего вопроса уже дан ответ.

2 голосов
/ 13 апреля 2011

1- *it разыменовывает элементы вектора plans и передает их в c.add по значению. Итак, правильно, копия каждого элемента вектора plans временно создается в переменной p (аргумент метода add) и затем добавляется в вектор plans класса Carrier.

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

3- Нетрудно понять, как работает конструктор копирования, сгенерированный компилятором. Просто предположим, что каждый атрибут переданного объекта копируется в объект, для которого вызывается конструктор копирования.

2 голосов
/ 13 апреля 2011

В main.c, передается ли аргумент функции Carrier.add () (* it), ссылка или копия объекта плана, который я вставил в вектор, или что-то еще?

Это копия, потому что вы объявили add() как void add(Plan p);. Если вы хотите передать ссылку, то она должна быть объявлена ​​как void add(Plan& p);.

Когда этот аргумент добавляется к вектору планов перевозчика (внутри класса перевозчика), добавляется ли копия? Как это работает, так как я не предоставил конструктор копирования и не сказал ему сделать копию? Я думаю, что это автоматически генерируется?

Да. Компилятор генерирует это для вас. См. здесь для получения более подробной информации.

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

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

2 голосов
/ 13 апреля 2011

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

Если вам нужна ссылка, вам нужно создать такую ​​функцию:

void Carrier::add(Plan const & p)

Вы передаете const объект Plan здесь, потому что вы ничего не меняете в нем в функции.Это считается хорошей практикой в ​​C ++, если вы не собираетесь вносить изменения в аргумент и передаете его по ссылке или указателю по этому вопросу, сделайте его const.

В ответ на ваш второй вопрос,контейнеру (std :: vector) в этом случае передается копия.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...