C ++浅/深拷贝?

时间:2011-09-23 19:09:20

标签: c++ reference pass-by-reference deep-copy

我有这个功能

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 :(得分:0)

这实际上取决于你的赋值运算符,这里没有列出。

该行

output=a_attributes[index];

将使用赋值运算符来设置输出。如果该赋值运算符进行深层复制,那么就可以获得深层复制。

答案 1 :(得分:0)

如果你没有重载赋值运算符,那么不会,你将得不到浅拷贝。分配output=a_attributes[index];时,您正在制作a_attributes[index]的副本。因此,对返回值的任何修改都不会影响a_attributes

如果你想要一个浅拷贝,那么你必须要overload the assignment operator,或者通过引用传递一个指针,把参数改为RELATION& *output,然后传入一个指针,然后改变最后一个行到output=&a_attributes[index];

您的代码还有另一个问题。您无法直接将字符串与==中的if(name==a_attributes[i].str_name)进行比较,因为只有字符串存储在同一位置时才会返回true。您需要使用类似strcmp()的内容。

答案 2 :(得分:0)

不,因为你在这里是一份深刻的副本。 output参数是对类RELATION的某个对象的引用。因此,如果您在getrelation函数中更改该对象,则用户将注意到这些更改,因为您更改了引用的对象。但是,在这一行 - output=a_attributes[index];上,您基本上调用了对象output的复制赋值运算符,该运算符执行a_attributes[index]返回的对象中每个字段的深层副本到output引用的对象。 {1}},除非复制赋值运算符过载并执行不同的操作。这基本上是因为您无法更改引用的值 - 例如,它不能引用一个对象并最终引用另一个对象。要实现你想要的东西(如果我说得对你好),你必须将指针传递给指向对象的指针(或对指针的引用),然后你可以通过取消引用它来改变指向该对象的指针。像这样:

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;
    }

希望它有所帮助!

答案 3 :(得分:0)

否...如果要获取对输出对象的引用,则将类型为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::mapstd::vector),则指针将指向无效的存储位置。因此,您必须确保容器超出您用作对象引用的指针。

答案 4 :(得分:0)

这里有一些更惯用的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重载,返回const Relation&