C++ 给定一个类的对象数组,类成员向量的内存分配有问题吗?

C++ 给定一个类的对象数组,类成员向量的内存分配有问题吗?,c++,class,object,vector,memory-address,C++,Class,Object,Vector,Memory Address,我的基本程序结构如下: class B1 { vector <someStruct> aStruct; //some struct contains a vector of 'someotherStruct's, etc B1() { cout << &aStruct << " ";}; }; class B2 {B1* pB1;}; class A { B1 object_B1; B2 object_B2;

我的基本程序结构如下:

class B1 
{
    vector <someStruct> aStruct; //some struct contains a vector of 'someotherStruct's, etc
    B1() { cout << &aStruct << " ";};
};


class B2 {B1* pB1;};

class A
{
    B1 object_B1;
    B2 object_B2;

    A() { objectB2.pB1 = &object_B1;}; 
};

int main()
{
    vector <A> someA;
    for(int q=0; q < N; q++)
        someA.push_back(A()); 

    cout << endl;

    for (int q=0; q < N; q++)
        cout << someA[q].B2.pB1 << " ";
}
因此,如果N为5,则输出为: 0xbffff828 0xbffff828 0xbffff828 0xbffff828 0xbffff828 0xbffff828\n 0xbffff828 0xbffff828 0xbffff828 0xbffff828 0xbffff828 0xbffff828 0xbffff828


换句话说,每个对象的向量在内存中占据相同的空间。程序输出也证明了这一点,因为通过不同的对象访问向量中的数据会得到相同的值,即使它们应该是不同的。当然,另一件奇怪的事情是,它给了我向量和对象相同的地址

忽略程序中的大量错误

A.push_back(A());
这将创建类型为a的临时对象。对象_B2.pB1成员变量初始化为指向此临时对象的对象_B1成员变量

然后将该临时对象复制到someA容器中。此副本的object_B1成员变量的地址不同,但您不会更新object_B2.pB1成员变量以指向新实例。要做到这一点,您需要实现一个复制构造函数,为了正确性,您还需要实现一个复制赋值操作符


所有指针最终都是相同的原因是临时对象都是在内存中的同一位置创建的,这使得,因为您可能在循环中调用push_,因此,在循环的每次迭代中,可以在堆栈上相同的位置创建临时对象。

忽略程序中的大量错误

A.push_back(A());
这将创建类型为a的临时对象。对象_B2.pB1成员变量初始化为指向此临时对象的对象_B1成员变量

然后将该临时对象复制到someA容器中。此副本的object_B1成员变量的地址不同,但您不会更新object_B2.pB1成员变量以指向新实例。要做到这一点,您需要实现一个复制构造函数,为了正确性,您还需要实现一个复制赋值操作符


所有指针最终都是相同的原因是临时对象都是在内存中的同一位置创建的,这使得,因为您可能在循环中调用push_,因此,在循环的每次迭代中,可以在堆栈上相同的位置创建临时对象。

您缺少一个用于a的复制ctor,默认的复制语义将指针值从一个B2对象复制到另一个B2对象。结构中的每个项都可以看到相同的地址,因为它们都是从同一个源对象复制的。当这个指向的对象稍后被销毁时,您将有UB访问它

A a1;
A a2 = a1;
assert(a2.object_B2.pB1 == &a1.object_B1);  // Danger Will Robinson!
修复方法:

struct A {
  B1 object_B1;
  B2 object_B2;

  A() { objectB2.pB1 = &object_B1; }
  A(A const &x)
  : object_B1 (x.object_B1)
  {
    object_B2.pB1 = &object_B1;
  }
};

您还需要一个复制分配操作符,因为默认操作符也有类似的问题。如果要禁用此op=,请将其声明为private,而不定义它。

您缺少一个用于a的复制ctor,默认的复制语义将指针值从一个B2对象复制到另一个B2对象。结构中的每个项都可以看到相同的地址,因为它们都是从同一个源对象复制的。当这个指向的对象稍后被销毁时,您将有UB访问它

A a1;
A a2 = a1;
assert(a2.object_B2.pB1 == &a1.object_B1);  // Danger Will Robinson!
修复方法:

struct A {
  B1 object_B1;
  B2 object_B2;

  A() { objectB2.pB1 = &object_B1; }
  A(A const &x)
  : object_B1 (x.object_B1)
  {
    object_B2.pB1 = &object_B1;
  }
};

您还需要一个复制分配操作符,因为默认操作符也有类似的问题。如果要禁用此op=,请将其声明为private,而不定义它。

语法错误太多。为什么人们在发布之前不尝试编译他们的示例代码呢?这么多语法错误。为什么人们在发布到这里之前不尝试编译他们的示例代码?@Nawaz:是的,它应该,而且会,这正是OP所要求的行为。默认的复制构造函数也应该复制地址。@Nawaz:这正是问题所在,请看我答案中的显式测试用例。@Fred和@James:我想我误读了这个问题,可能是因为它不够清楚。@Nawaz:是的,它应该,它会,这正是OP所问的行为。默认的复制构造函数也应该复制地址。@Nawaz:这正是问题所在,请看我答案中的显式测试用例。@Fred和@James:我想我误读了这个问题,可能是因为它不够清楚。我不明白复制构造函数的参数应该是什么。为什么我必须将对象_B1更改为x?我不能只更改object_B2.pB1中的值吗?@MattMunson:copy-ctor的参数是副本的源;在a2=a1中;,x是对a1的引用。如果我省略了“object_B1 x.object_B1”这一行,这是否意味着object_B1仍然与它从中复制的对象具有相同的地址?@MattMunson:这是一个构造函数初始值设定项;查一查。它与this->object_B1或x.object_B1的地址无关;它所做的是将一个对象的值复制到另一个对象,在本例中,该对象复制B1的向量数据成员。@Matt
蒙森:或多或少,是的。一个类几乎总是在C++中有一个拷贝cTor,编译器如果不声明一个,则生成一个,而拷贝cor意味着一个非常特定的签名集。查找三的规则可能会有所帮助。我不明白复制构造函数的参数应该是什么。为什么我必须将对象_B1更改为x?我不能只更改object_B2.pB1中的值吗?@MattMunson:copy-ctor的参数是副本的源;在a2=a1中;,x是对a1的引用。如果我省略了“object_B1 x.object_B1”这一行,这是否意味着object_B1仍然与它从中复制的对象具有相同的地址?@MattMunson:这是一个构造函数初始值设定项;查一查。它与this->object_B1或x.object_B1的地址无关;它所做的是将一个对象的值复制到另一个对象,在本例中,另一个对象复制B1的向量数据成员。@MattMunson:或多或少,是的。一个类几乎总是在C++中有一个拷贝cTor,编译器如果不声明一个,则生成一个,而拷贝cor意味着一个非常特定的签名集。查找三的规则可能会有所帮助。