相关疑难解决方法(0)

为什么对于非TriviallyCopyable的对象,未定义std :: memcpy的行为?

来自http://en.cppreference.com/w/cpp/string/byte/memcpy:

如果对象不是TriviallyCopyable(例如标量,数组,C兼容结构),则行为未定义.

在我的工作中,我们使用std::memcpy了很长时间来按比例交换不是TriviallyCopyable的对象:

void swapMemory(Entity* ePtr1, Entity* ePtr2)
{
   static const int size = sizeof(Entity); 
   char swapBuffer[size];

   memcpy(swapBuffer, ePtr1, size);
   memcpy(ePtr1, ePtr2, size);
   memcpy(ePtr2, swapBuffer, size);
}
Run Code Online (Sandbox Code Playgroud)

从来没有任何问题.

我理解滥用std::memcpy非TriviallyCopyable对象并导致下游的未定义行为是微不足道的.但是,我的问题是:

std::memcpy当与非TriviallyCopyable对象一起使用时,为什么它本身的行为是未定义的?为什么标准认为有必要指定?

UPDATE

http://en.cppreference.com/w/cpp/string/byte/memcpy的内容已经过修改,以回应这篇文章和帖子的答案.目前的描述说:

如果对象不是TriviallyCopyable(例如标量,数组,C兼容结构),则行为是未定义的,除非程序不依赖于目标对象(不运行memcpy)的析构函数的效果和生命周期目标对象(已结束,但未开始memcpy)由其他一些方法启动,例如placement-new.

PS

@Cubbi的评论:

@RSahu如果有东西保证UB下游,它会使整个程序不确定.但我同意在这种情况下似乎可以绕过UB并相应​​地修改cppreference.

c++ memcpy object-lifetime language-lawyer c++11

67
推荐指数
5
解决办法
5355
查看次数

是否在C11中定义了memcpy(&a + 1,&b + 1,0)?

这个问题遵循前一个关于定义的问题memcpy(0, 0, 0),该问题最终被确定为未定义的行为.

正如相关问题所示,答案取决于C11第7.1.4:1条的内容

除非在以下详细说明中另有明确说明,否则以下每个语句均适用:如果函数的参数具有无效值(例如函数域外的值,或程序地址空间外的指针,或空指针,[...])行为未定义.[...]

标准函数memcpy()需要指向void和const void,如下所示:

void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
Run Code Online (Sandbox Code Playgroud)

这个问题值得一问的,只是因为有很多标准的"有效"指针两个概念都:有可以有效地通过指针算术来获得,并且可以有效地相比指针<,>同一对象内部其他指针.并且有一些指针可用于解除引用.前一类包括"一个过去"指针,例如&a + 1和&b + 1下面的代码片段,而后一个类不包括这些指针有效.

char a;
const char b = '7';
memcpy(&a + 1, &b + 1, 0);
Run Code Online (Sandbox Code Playgroud)

如果将上述片段视为已定义的行为,memcpy()则根据void无论如何将参数键入为指针的事实,因此其各自有效性的问题不能解除对它们的解除引用.还是应该&a + 1和&b + 1被认为是"程序的地址空间之外"?

这对我很重要,因为我正在使标准C函数的效果正式化.我写的一个先决条件memcpy()是requires \valid(s1+(0 .. n-1));,直到有人指出我的注意,GCC 4.9已经开始积极优化这样的库函数调用超出了公式中表示上述( …

c language-lawyer c11 gcc4.9

32
推荐指数
2
解决办法
1425
查看次数

标签 统计

language-lawyer ×2

c ×1

c++ ×1

c++11 ×1

c11 ×1

gcc4.9 ×1

memcpy ×1

object-lifetime ×1