c++ 隐式复制构造函数是不是复制数组成员变量? [复制]

Posted

技术标签:

【中文标题】c++ 隐式复制构造函数是不是复制数组成员变量? [复制]【英文标题】:c++ does implicit copy constructor copy array member variable? [duplicate]c++ 隐式复制构造函数是否复制数组成员变量? [复制] 【发布时间】:2011-08-07 16:44:08 【问题描述】:

可能重复:How are C array members handled in copy control functions?

如果成员变量被声明为指针,我猜想隐式复制构造函数(由编译器生成)会复制指针。

我不确定数组成员变量会发生什么。

隐式复制构造函数是否正确复制数组成员?赋值运算符呢?

例如:

char mCharArray[100];
int mIntArray[100];   

mCharArray mIntArray 会被正确复制吗?

【问题讨论】:

【参考方案1】:

只是为了尽可能清楚:

struct X

    char data_[100];
;

X a, b;
a.data_[10] = 'x';
b = a;
// here, b.data_[n] == a.data_[n] for 0 <= n < 100, so b.data_[10] == 'x'

但是,可能令人讨厌的情况是指针和引用:

struct X

    char* data_[100];
;

X a, b;
a.data_[10] = new char[6]; // a character array on the heap
strcpy(a.data_[10], "hello"); // put some text into it...
b = a;
// here, b.data_[n] == a.data_[n] for 0 <= n < 100
//   so b.data_[10] == a.data_[10] == same character array containing "hello"
// BUT...
b.data_[10][2] = 'L';  // change text to "heLlo" via b.data_[10] pointer...
// here, a.data_[10][2] will be 'L' too, as a.data_[10] and b.data_[10] both point
// to the same underlying heap memory returned by new above...
delete[] a.data_[10];  // ok...
std::cout << b.data_[10];  // NOT ok - this memory's been deallocated!
delete[] b.data_[10];  // NOT ok - this memory's (already) been deallocated!

希望这有助于说明问题。

考虑一种使结构更“复制安全”的方法:

struct X

    X(const X& rhs)
    
        for (int i = 0; i < 100; ++i)
            if (rhs.data_[i])
            
               // deep copy of pointed-to text...
               data_[i] = new char[strlen(rhs.data_[i]) + 1];
               strcpy(data_[i], rhs.data_[i]);
            
            else
               data_[i] = NULL;
    
    char* data_[100];
;

这里,复制构造函数使X b = a 更安全、更直观,因为它自己复制所有字符串数据,并且不再依赖或连接到复制的X 对象,但这更慢并且可能更浪费内存。

【讨论】:

【参考方案2】:

是的。复制构造函数和赋值运算符在 C/C++ 中内置提供。他们逐字节复制(这对较大的数组不利,因为它会导致代码膨胀)。它也复制指针,但这将是浅拷贝(如果指针指向某个位置,则复制的指针也将指向同一位置)。

【讨论】:

不,他们逐个复制成员。 @iammilind:“逐字节复制……不适合更大的数组……导致代码膨胀”……显然,“更大”排除了唯一轻微的“代码膨胀”情况: 数组如此之小,编译器会展开循环作为性能优化。对于较大的数组,编译器将生成一个循环或进行函数调用(对 memcpy() 之类的东西),因此无论数组大小如何,生成的代码量都是恒定的。 @Tony,感谢您提供的信息。我不知道编译器有这样的优化器。 @iammilind:不客气。实际上,unapersson 提到的逐个成员复制通常是通过一个循环依次为数组中的每个元素调用复制构造函数来完成的,因此即使关闭优化,您也可以确信大小恒定。优化案例是循环展开和/或函数调用。干杯。 @Tony,这意味着,如果我们没有要“深度复制”的指针成员,那么可以摆脱实现复制构造函数(和operator =)并依赖内置-实施中?【参考方案3】:

“隐式复制构造函数(由编译器生成)” - 对所有变量进行浅拷贝。

【讨论】:

这里的浅拷贝是什么意思?有问题的数组中的元素是浅拷贝的? 浅拷贝意味着它不是“深拷贝”指向或引用的值。换句话说,如果你浅拷贝一个指针或引用,你最终会得到两个指向同一个对象的指针或引用(并且可能需要注意不要过早地释放它或两次)。深拷贝也会复制/克隆指向或引用的对象,因此包含指针/引用的对象有自己的“自己的”副本,独立于复制的对象。 @Tony:我原来的问题可以改写为“数组成员是浅拷贝还是拷贝了指向数组的指针?”我不是在问数组的成员是否被深度复制。 @Eugene:考虑它的最佳方式是根据两个变量:如果您有X a = ...; X b = a;,那么除非 X 对象提供该语义行为(例如 int、双精度、向量、字符串,但不是普通的指针或引用)。如果 a 和 b 是数组和成员变量,则完全相同,并且逐个元素地应用。规则是一致的。【参考方案4】:

是的,是的就是答案。 C 中的结构也是如此。

typedef struct 
    int a[100];
 S;

S s1;
s1.a[0] = 42;
S s2;
s2 = s1;    // array copied

【讨论】:

我希望你的回答是正确的。其他人的回答让我很困惑:( @Eugene 人们似乎对此很重视。我的回答是正确的——正如我所说,C 的工作方式完全相同。 人们对此做了大量工作,因为他们试图解释包含指针和引用的结构稍微复杂一些的情况。目前尚不清楚该案例是否有必要回答这个问题,但它已经足够接近,以至于其他答案显然感觉最好让尤金也知道这一点...... @Tony 不幸的是,除了你的答案之外的所有其他答案实际上都是不正确的,我发现你的答案很难理解。我也不认为我们应该鼓励使用 strdup! 我认为值得添加 s2.a[0] = 43; std::cout &lt;&lt; s1.a[0] &lt;&lt; std::endl; // 42 只是为了说明它实际上是复制的,而不仅仅是指向数据的指针。

以上是关于c++ 隐式复制构造函数是不是复制数组成员变量? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

使用与 C++ 标准允许的成员变量相同的名称为构造函数参数初始化成员变量? [复制]

c++ 拷贝构造函数与赋值运算符重载函数的区别是

复制控制函数中如何处理 C++ 数组成员?

在 C++0x 中,非静态数据成员初始化器会覆盖隐式复制构造函数吗?

C++学习基础六——复制构造函数和赋值操作符

我定义了一个非拷贝构造函数;复制构造函数是不是仍会被隐式定义?