C ++ мелкая / глубокая копия? - PullRequest
       27

C ++ мелкая / глубокая копия?

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

У меня есть эта функция

int getrelation(string name, RELATION& output){

        bool found=0;
        int index=0;
        for(int i=0;i<a_attributes.size();i++){
            if(name==a_attributes[i].str_name){
                found=1;
                index=i;
            }
        }
        if(!found){
            printf("relation not found");
            return 1;
        }
        output=a_attributes[index];  

        return 0;
    }

ОТНОШЕНИЕ это класс a_attributes - это вектор отношений.

предполагается возвращать ссылку на объект отношения. После вызова getrelation(), если я изменю значения вывода, то значения a_attributes[index] также должны быть изменены, потому что это мелкая копия, верно?

Ответы [ 5 ]

0 голосов
/ 23 сентября 2011

Вот еще немного идиоматического C ++, хотя возвращение фактического итератора также может быть хорошей идеей.

struct rel_by_name : public std::binary_function<const std::string&, const RELATION&, bool> {
  bool operator()(const std::string& s, const RELATION& rel) {
    return s == rel.str_name;
  }
};

RELATION& getrelation(const std::string& name) {
  std::vector<RELATION>::iterator it = std::find_if(a_attributes.begin(), a_attributes.end(),
                                                    std::bind1st(rel_by_name(), name));
  if(it == a_attributes.end()) {
    //not found, report error by throwing or something
  }
  else { return *it; }
}

Вы можете добавить константную перегрузку, возвращающую const Relation&.

0 голосов
/ 23 сентября 2011

Нет ... если вы хотите получить ссылку на выходной объект, то передайте ссылку на указатель типа RELATION в функцию, а не ссылку на объект типа RELATION.

Например:

int getrelation(string name, RELATION*& output)
{
    bool found=0;
    int index=0;
    for(int i=0;i<a_attributes.size();i++){
        if(name==a_attributes[i].str_name){
            found=1;
            index=i;
        }
    }
    if(!found){
        printf("relation not found");
        return 1;
    }
    output = &(a_attributes[index]);  //take the address-of object

    return 0;
}

Затем вы бы назвали свою функцию так:

RELATION* ptr_to_object = NULL;
string argument_name;
//...more code to initialize argument_name

if (getrelation(argument_name, ptr_to_object) == 1)
{
    //...handle error condition
}

//now ptr_to_object points to your a_attribute[index] object

Итак, теперь вы можете разыменовать ptr_to_object, и вы получите объект в a_attribute[index].Затем вы можете изменить атрибуты этого объекта путем разыменования указателя.Единственное предупреждение заключается в том, что вы не должны вызывать delete на ptr_to_object, поскольку он не «владеет» объектом, на который указывает объект, и возвращаемый указатель не указывает на начало сегмента памяти, выделенного с помощью new.Кроме того, если контейнер a_attribute избавляется от объекта (то есть, если это std::map или std::vector), тогда указатель будет указывать на недопустимое расположение в памяти.Таким образом, вы должны убедиться, что контейнер превосходит указатель, который вы используете в качестве ссылки на объект.

0 голосов
/ 23 сентября 2011

Если вы не перегружены оператором присваивания, то нет, вы не получите мелкую копию.Когда вы назначаете output=a_attributes[index];, вы делаете копию a_attributes[index].Таким образом, любые изменения возвращаемого значения не будут влиять на a_attributes.

. Если вы хотите получить мелкую копию, вам придется либо перегрузить оператор присваивания , либо передать указатель с помощьюссылка, изменяя аргумент на RELATION& *output и передавая указатель, затем изменяя последнюю строку на output=&a_attributes[index];.

Существует также другая проблема с вашим кодом.Вы не можете сравнивать строки напрямую с ==, как у вас в строке if(name==a_attributes[i].str_name), потому что он вернет true, только если строки хранятся в одном месте.Вам нужно использовать что-то вроде strcmp().

0 голосов
/ 23 сентября 2011

Нет, потому что вы здесь глубокая копия. Параметр output является ссылкой на некоторый объект класса RELATION. Поэтому, если вы измените этот объект в функции getrelation, тогда пользователь заметит эти изменения, потому что вы измените объект, на который есть ссылка. Однако в этой строке - output=a_attributes[index]; вы, по сути, вызываете оператор присваивания копии объекта output, который делает глубокое копирование каждого поля из объекта, возвращенного a_attributes[index], в объект, на который ссылается output, если только не назначено копирование. Оператор перегружен и делает что-то другое. Это в основном потому, что вы не можете изменить значение ссылки - например, он не может ссылаться на один объект и в конечном итоге ссылаться на другой. Чтобы достичь того, что вы хотите (если я вас правильно понял), вам нужно передать указатель на указатель на объект (или ссылку на указатель), затем вы можете изменить указатель на объект, сняв с него ссылку. Примерно так:

int getrelation(string name, RELATION **output){
        bool found=0;
        int index=0;
        for(int i=0;i<a_attributes.size();i++){
            if(name==a_attributes[i].str_name){
                found=1;
                index=i;
            }
        }
        if(!found){
            printf("relation not found");
            return 1;
        }
        *output= &a_attributes[index];
        return 0;
    }

Надеюсь, это поможет!

0 голосов
/ 23 сентября 2011

Это действительно зависит от вашего оператора присваивания, который здесь не указан.

Линия

output=a_attributes[index];

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

...