将std::vector作为输入/输出引用参数传递时丢失了一些数据

Some data lost while passing std::vector as in/out reference parameter

本文关键字:数据 参数传递 输出 vector std 输入 引用      更新时间:2023-10-16

我在函数之间传输矢量中包含的一些数据时遇到问题。情况如下:

void generateObjects(std::vector<MyClass> &objects)
{
    objects.clear();
    //Fill objects vector
    std::vector<MyClass> p;
    //This 4-line pattern is repeated a number of times to generate all objects and store them in variable 'objects'
    p.clear();
    generateSomeOfTheObjects(p); //p is again passed by ref. in/out parameter
    for(uint j = 0; j < p.size(); p++){
        objects.push_back(p[j]);
    }
    //Print some members of the objects - works fine
    for(uint i = 0; i < objects.size(); i++){
        printf("%f ",objects[i].mymember->myElm);
    }
}
int main()
{
   std::vector<MyClass> objects;
   generateObjects(objects);
   //Print size of vector - size is correct it is the same as it is in generateObjects func
   printf("%lun",objects.size());
   //Again print members of the objects - some members are retained after the function call, some are lost. 
   //The one below doesn't work, mymember is a pointer to another object and its member myElm seems not initialized.
   for(uint i = 0; i < objects.size(); i++){
       printf("%f ",objects[i].mymember->myElm);
   }
   //Here I need to pass the objects to another read-only function
   ...
}

我在互联网上搜索过类似的案例,实际上发现了很多,但我无法对我的代码应用相同的修复程序。我正在尝试访问MyClass实例(objects[I].mymember->myElm)的成员所指向的对象的成员,这里可能缺少什么?

可能错误在于MyClass的实现。我想说,这个类包含一些用局部变量的地址初始化的指针,所以当你从一些函数返回时,指针指向一个被破坏的对象。

这将未定义的行为,但可能会偶然工作。当您从第一个函数返回时,堆栈内存最终会被覆盖,数据也会丢失。

更新:感谢@chris在下面的评论中的见解,最可能的原因是您的MyClass没有复制构造函数,但它有一个指针成员。

类似这样的东西:

class MyClass
{
public:
    Member *mymember;
    MyClass()
    {
        mymember = new Member;
    }
    ~MyClass()
    {
        delete mymember;
    }
};

现在,如果使用编译器生成的默认复制构造函数(或复制运算符),会发生什么?

void foo()
{
    MyClass a;
    {
        MyClass b(a);
    }
    //a.mymember is no longer valid
}

ab共享相同的指针mymember,因此当其中一个被破坏时,mymember被删除,而另一个持有悬挂指针。

这就是为什么我们有三规则。它指出:

无论何时定义非默认析构函数,都很可能需要一个非默认复制构造函数和一个非缺省复制运算符。

现在,您必须决定是要共享mymember的所有权,还是要复制它。第一个最好使用智能指针(shared_ptr),第二个最好使用深度复制。

例如,深度复制:

class MyClass
{
public:
    Member *mymember;
    MyClass()
    {
        mymember = new Member;
    }
    MyClass(const MyClass &c)
    {
        mymember = new Member(c.mymember);
    }
    MyClass &operator=(const MyClass &c)
    {
        if (this != &c) //be aware of self-copy
        {
            delete mymember;
            mymember = new Member(c.mymember);
        }
        return *this;
    }
    ~MyClass()
    {
        delete mymember;
    }
};

与共享指针:

class MyClass
{
public:
    std::shared_ptr<Member> mymember; //or boost::shared_ptr if old compiler
    MyClass()
        :mymember(new Member)
    {
    }
    //no custom-made destructor -> no rule of 3
};

也许与您的问题无关,但这是:

void generateObjects(std::vector<MyClass> &objects)
{
  objects.clear();
  std::vector<MyClass> p;
  p.clear();
  generateSomeOfTheObjects(p);
  for(uint j = 0; j < p.size(); p++){
      objects.push_back(p[j]);
  }
  for(uint i = 0; i < objects.size(); i++){
      printf("%f ",objects[i].mymember->myElm);
  }
}

与此相同:

void generateObjects(std::vector<MyClass> &objects)
{
  objects.clear();
  generateSomeOfTheObjects(objects);
  std::reverse(objects.begin(), objects.end()); 
  for(uint i = 0; i < objects.size(); i++) {
      printf("%f ",objects[i].mymember->myElm);
  }
}

正如@rodrigo所提到的,复制问题是您没有使用复制构造函数进行深度复制。

相关文章: