C++ 将std::memcpy用于非平凡可复制类型的对象

C++ 将std::memcpy用于非平凡可复制类型的对象,c++,types,C++,Types,该标准定义了我们可以通过以下方式使用std::memcpy int: 对于任何普通的可复制类型T,如果两个指向T的指针指向 不同的T对象obj1和obj2,其中obj1和obj2都不是 基类子对象,如果构成obj1的基础字节(1.7)为 复制到obj2中,obj2随后应保持与obj1相同的值 如果我们将该函数应用于非平凡可复制类型的对象,可能会遇到什么潜在问题?以下代码的工作方式与普通可复制类型类似: #include <iostream> #include <cstring&

该标准定义了我们可以通过以下方式使用std::memcpy int:

对于任何普通的可复制类型T,如果两个指向T的指针指向 不同的T对象obj1和obj2,其中obj1和obj2都不是 基类子对象,如果构成obj1的基础字节(1.7)为 复制到obj2中,obj2随后应保持与obj1相同的值

如果我们将该函数应用于非平凡可复制类型的对象,可能会遇到什么潜在问题?以下代码的工作方式与普通可复制类型类似:

#include <iostream>
#include <cstring>

using std::cout;
using std::endl;

struct X
{
    int a = 6;
    X(){ }
    X(const X&)
    {
        cout << "X()" << endl;
    }
};

X a;
X b;
int main()
{
    a.a = 10;
    std::memcpy(&b, &a, sizeof(X));
    cout << b.a << endl; //10
}
#包括
#包括
使用std::cout;
使用std::endl;
结构X
{
INTA=6;
X(){}
X(常数X&)
{
难道你问:

如果我们将该函数应用于非平凡可复制类型的对象,可能会遇到什么潜在问题

下面是一个非常简单的示例,说明了对非平凡可复制类型的对象使用
std::memcpy
的问题

#include <cstring>

struct A
{
   A(int size) : size_(size), data_(new int[size]) {}
   ~A() { delete [] data_; }

   // The copy constructor and the copy assignment operator need
   // to be implemented for the class too. They have been omitted
   // to keep the code here minimal.

   int size_;
   int* data_;
};

int main()
{
   A a1(10);
   A a2(20);
   std::memcpy(&a1, &a2, sizeof(A));

   // When we return from the function, the original data_ of a1
   // is a memory leak. The data_ of a2 is deleted twice.

   return 0;
}
#包括
结构A
{
A(int-size):size(size),data(newint[size]){
~A(){delete[]数据}
//复制构造函数和复制赋值运算符需要
//也要为类实现。它们已被省略
//使这里的代码保持最少。
int-size_389;;
int*数据;
};
int main()
{
A a1(10);
A a2(20);
std::memcpy(&a1,&a2,sizeof(A));
//当我们从函数返回时,a1的原始数据
//是内存泄漏。a2的数据被删除两次。
返回0;
}
考虑以下程序:

#include <memory>

int main() {
    std::shared_pointer<int> x(new int);

    {
        std::shared_pointer<int> y;
        memcpy((void*)&y, (void*)&x, sizeof(x));
    }

    *x = 5;
}
#包括
int main(){
std::共享_指针x(新int);
{
std::共享_指针y;
memcpy((void*)和y,(void*)和x,sizeof(x));
}
*x=5;
}
因为我们使用
memcpy
而不是赋值运算符将
x
复制到
y
,所以引用计数没有得到更新。因此,在该块末尾,调用了
y
的析构函数。它发现它的引用计数为1,这意味着它是指向堆al的唯一共享_指针实例定位整数。所以它会删除它


最后一行<代码>主< /代码>很可能是分段错误,因为<代码> x>代码>指向一个已删除的对象。

明显的UB是明显的。例如,考虑<代码> MycPy < /代码>:a <代码> STD::vector < /代码>,例如,是的,它是有效的,因为结构X是简单的可复制的。如果结构的成员包括任何类型的堆例如,内存,那么您就会遇到问题。好吧,在实际的程序中。在您的测试中没有。@Wlerin X是不可复制的。@T.C.Mmm。它有一个不可复制的复制构造函数。从技术上讲,这可能足以使它不可复制,但类的实际内容可以一个成员一个成员地复制,而不会出现问题。C之前++11,b=a的结果也将与memcpy的结果相同。无论如何,这个示例程序都不是一个好的示例。您的实际问题是什么?您想让我们向您解释什么是未定义的行为?还是您只想确认这实际上是未定义的行为?实际上,向运算符dele传递无效指针很高兴我能回答你的问题。@DmitryFucintv,不客气。