简体   繁体   English

C++:从复制构造函数外部修改 object 成员时,向量 memory 损坏,但从内部修改时不会损坏

[英]C++: vector memory corruption when modifiying an object member from outside the copy constructor but not when modifying from within

#include <iostream>
#include <vector>
#include <cassert>

class a_class
{
public:

    int num_IN;

    a_class():num_IN(0){}
    a_class(a_class const & origin){/*Initialise();*/}   //if not called here, error occurs

    void Initialise(){num_IN =5;}
};

int main () 
{
    std::vector <a_class> the_vector;

    for(int q=0; q < 30; q++)
    {
        the_vector.push_back(a_class());
        the_vector[q].Initialise();             
        assert(5 == the_vector[q].num_IN);      //no problem here
    }

    for(int q=0; q < 30; q++)
        assert(the_vector[q].num_IN == 5);      //assertion fails
}

I don't understand the difference between calling this from outside vs. inside the CC.我不明白从外部调用此调用与从 CC 内部调用之间的区别。 I also don't know why it should cause a problem in any case.我也不知道为什么无论如何它都会引起问题。

std::vector may reallocate the buffer it uses if it's size outgrows it, in which case it has to copy the old elements over to the new buffer.如果std::vector的大小超过它,它可能会重新分配它使用的缓冲区,在这种情况下,它必须将旧元素复制到新缓冲区。 If you don't have a proper copy constructor that copies num_IN over, the old value is lost.如果您没有适当的复制构造函数来复制num_IN ,则旧值将丢失。

Fix this by providing a proper copy constructor:通过提供适当的复制构造函数来解决此问题:

a_class(a_class const & origin) : num_IN(origin.num_IN) {}

In the code posted the copy constructor isn't even needed - if you don't provide one the compiler will generate a suitable one here.在发布的代码中,甚至不需要复制构造函数——如果你不提供一个,编译器会在这里生成一个合适的。

The std::vector class may have to reallocate the underlying dynamic array when you are repeatedly calling push_back() to append new elements.当您重复调用push_back()到 append 新元素时, std::vector class 可能必须重新分配底层动态数组。 The usual strategy is for std::vector to increase the size of the underlying buffer by a factor, possibly a factor of 2 .通常的策略是std::vector将底层缓冲区的大小增加一个因子,可能是因子2

When this reallocation does occur, the copy constructor (or the move constructor if you've defined one and are using c++0x ) is called to copy the vector's elements from the old buffer to the new one.当这种重新分配确实发生时,将调用复制构造函数(或移动构造函数,如果您已定义并使用c++0x )将向量的元素从旧缓冲区复制到新缓冲区。

Your copy constructor is not actually copying properly, you should be assigning the num_IN parameter:您的复制构造函数实际上没有正确复制,您应该分配num_IN参数:

a_class(a_class const& src): num_IN(src.num_IN) {}

Typically, with STL containers, the data types stored should obey the " rule of three " in that the constructor, copy constructor, assignment operator and destructor all work together robustly.通常,对于STL容器,存储的数据类型应遵循“三规则”,即构造函数、复制构造函数、赋值运算符和析构函数都可以稳健地协同工作。

With move semantics in c++0x I guess this should be extended to the "rule of five" in that you should also consider properly defined move constructors and move assignment operators.使用c++0x中的移动语义,我想这应该扩展到“五规则”,因为您还应该考虑正确定义的移动构造函数和移动赋值运算符。

The problem is because of the push_back , your vector reallocates the memory in the first for loop whenever vector's size increases beyond its capacity .问题是由于push_back ,只要向量的size超过其capacity ,您的向量就会在第一个for循环中重新分配 memory 。 During this reallocation vector copies the objects already present in it by invoking the copy constructor.在此重新分配vector期间,通过调用复制构造函数复制已存在于其中的对象。 Since your copy constructor is not correct (You are not doing anything there), the initialized value is not carried over during reallocation.由于您的复制构造函数不正确(您没有在那里做任何事情),初始化值不会在重新分配期间结转。

Your copy constructor isn't doing anything.您的复制构造函数没有做任何事情。 It should be saying num_IN = origin.num_IN;应该说 num_IN = origin.num_IN;

AHhh,啊,

I can see what is happening.我可以看到正在发生的事情。

In the first loop you are pushing back object to the vector, each time you push back the vector is resized and copy constructor is called on all the elements in the vector already.在第一个循环中,您将 object 推回向量,每次推回向量时都会调整大小,并且已经在向量中的所有元素上调用了复制构造函数。 Since you have overwritten the copy constructor not to do anything, num_IN is left uninitialized.由于您已经覆盖了复制构造函数而不做任何事情,因此 num_IN 未初始化。

to make it work.让它工作。 i would reenable to copy constructor to do member wise copy.我将重新启用复制构造函数以进行成员明智的复制。

Alternatively.或者。

i would resize the vector to the required size.我会将矢量调整为所需的大小。 This way, vector is not resized each time you add an extra element这样,每次添加额外元素时都不会调整向量的大小

std::vector <a_class> the_vector;
the_vector.resize(30);

for(int q=0; q < 30; q++)
{
    the_vector[q].Initialise();             
    assert(5 == the_vector[q].num_IN);      //no problem here
}

for(int q=0; q < 30; q++)
    assert(the_vector[q].num_IN == 5);      //assertion fails

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当从 function 返回 object 时,会调用 C++ 中的复制构造函数? - Copy Constructor in C++ is called when object is returned from a function? 从C ++的构造函数中向成员const char *变量分配字符串文字时会发生什么? - What happens when assigning a string literal to a member const char* variable from within a constructor in C++? 从 C++ 中的 class 外部修改 class 的成员 - Modifying the member of a class from outside the class in C++ 从共享指针向量中删除元素时 Memory 损坏 - Memory corruption when removing elements from a vector of shared pointers C++ 在向量内修改 class object - C++ Modifying class object within a vector cin在C ++中时发生内存损坏 - Memory corruption when cin in c++ 从函数返回对象时,使用自定义复制构造函数的C ++? - C++ using custom copy constructor when object returned from a function? 为什么在C ++中允许从外部修改常量对象的指针成员变量的内存? - Why is it allowed in C++ to modify a constant object's pointer member variable's memory from outside? 修改 C++ 向量时,最好是复制向量还是使用带互斥锁的引用? - When modifying a C++ vector, is it best to copy the vector or use a reference with mutex locking? 再次调用构造函数时,对象的C ++私有成员被修改 - C++ private member of object is modified when calling constructor again
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM