Tag: 语言律师

为什么对于不是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); } 从来没有任何问题。 我明白,滥用std::memcpy与非TriviallyCopyable对象并导致下游未定义的行为是微不足道的。 不过,我的问题是: 为什么在使用非TriviallyCopyable对象时, std::memcpy本身的行为是未定义的? 为什么标准认为有必要指定? UPDATE http://en.cppreference.com/w/cpp/string/byte/memcpy的内容已经被修改,以回应这个post和post的答案。 目前的描述说: 如果对象不是TriviallyCopyable (例如标量,数组,C兼容结构),则行为是不确定的,除非程序不依赖于目标对象(不由memcpy运行)的析构函数的效果以及目标对象(已结束,但未由memcpy启动)通过其他方式启动,如placement-new。 PS 评论者@Cubbi: @RSahu如果有东西保证UB下游,它呈现整个程序未定义。 但我同意,在这种情况下,似乎有可能绕过UB,并相应地修改相关的参考。

序列点和部分顺序

几天前, 这里有一个关于这个expression的讨论 我= ++ i + 1 调用UB(未定义的行为)或不。 最后得出的结论是它调用UB,因为'i'的值在两个序列点之间不止一次地改变。 我参与了与Johannes Schaub的讨论。 按照他的说法 i =(i,i ++,i)+1 ——(1)/ *也调用UB * / 我说(1)不会调用UB,因为前面的子expression式的副作用是由逗号操作符','在i和i ++之间以及在i ++和i之间清除的。 然后他给出了以下解释: “是的,在i ++之前完成所有副作用之后的顺序点,但是没有任何东西阻止了分配副作用与i ++的副作用重叠。 根本的问题是分配的副作用没有被指定为在在对赋值的两个操作数进行评估之前,所以序列点在保护这一点上不能做任何事情:序列点引起一个偏序:只是因为在++之后和之后有一个序列点并不意味着所有的副作用都被序列化关于我 。 另外,请注意,仅仅一个序列点就意味着什么:评估顺序不是由代码forms决定的。 这是由语义规则决定的。 在这种情况下,没有语义规则说明何时分配副作用发生在评估这些操作数的操作数或子expression式方面。 以“大胆”写的陈述让我感到困惑。 我所知道的: “在执行顺序中的某些特定点称为顺序点,以前评估的所有副作用应该是完整的,并且不会发生后续评估的副作用。 因为,逗号运算符也指定了执行顺序,当我们到达最后的i时,i ++的副作用已经被取消了。如果没有指定评估顺序,那么他(Johannes)会是正确的(但是在逗号运算符的情况下, )。 所以我只想知道(1)是否调用UB? 有人能给出另一个有效的解释吗 谢谢!

负数在C中的表示?

C代表负整数? 是通过补码表示还是通过使用MSB(最高有效位)? hex中的-1是ffffffff 。 所以请为我澄清这一点。

什么是适用于SFINAE的C ++ 11标准中提到的“直接上下文”?

C ++ 11标准第14.8.2 / 8段规定了replace失败应该或不应该导致“硬”编译错误(从而导致编译失败)或“软”错误的条件导致编译器从重载parsing的候选集合中丢弃一个模板(不会使编译失败,并启用众所周知的SFINAE成语): 如果replace导致无效的types或expression式,则键入演绎失败。 无效的types或expression式是使用replace参数编写的格式不正确的types或expression式。 [注意:访问检查是替代过程的一部分。 -end note] 只有函数types及其模板参数types的上下文中的无效types和expression式才会导致扣除失败 。 […] 在“整个C ++ 11标准”中,“ 直接上下文 ”这个词只出现了8次,每次它们跟随(或作为其一部分出现)下列(非规范性)文本的实例: [注意: 替代types和expression式的评估可能导致副作用,例如类模板特化和/或函数模板特化的实例化,隐式定义函数的生成等。这些副作用不在“即时上下文“,并可能导致程序不合格。 – 注意] 这个注释给出了直接上下文意味着什么(不是非常慷慨的)暗示,但是至less对于我来说,这往往不足以决定replace是否应该导致“硬”编译错误。 题: 你能提供一个解释,一个决策程序,和/或一些具体的例子来帮助搞清楚在哪些情况下,replace错误在函数types及其模板参数types的“ 直接上下文 ”中是否发生?

对“模式”,“阶级”和“types”的事物types进行全面考察是不够的

语言R混淆了我。 实体有模式和类 ,但即使这样也不足以充分描述实体。 这个答案说 在R中,每个“对象”都有一个模式和一个类。 所以我做了这些实验: > class(3) [1] "numeric" > mode(3) [1] "numeric" > typeof(3) [1] "double" 到目前为止还不够公平,但是我传递了一个向量: > mode(c(1,2)) [1] "numeric" > class(c(1,2)) [1] "numeric" > typeof(c(1,2)) [1] "double" 这没有意义。 当然,整数向量应该有一个不同的类或不同的模式,而不是一个整数? 我的问题是: R中的所有东西都有(正好一个) 类吗? R中的所有东西都有(恰好一种) 模式吗? 如果有的话,“typeof”告诉我们什么? 还需要其他什么信息来完整描述实体? (例如,“vector性”存储在哪里?) 更新 :显然,文字3只是一个长度为1的向量。没有标量。 OK但是…我尝试mode("string")并得到"character" ,导致我认为一个string是一个字符的vector。 但如果这是真的,那么这应该是真实的,但它不是! c('h','i') == "hi"

将constexpr标准库函数视为constexpr是否符合编译器扩展?

gcc编译下面的代码而没有警告: #include <cmath> struct foo { static constexpr double a = std::cos(3.); static constexpr double c = std::exp(3.); static constexpr double d = std::log(3.); static constexpr double e1 = std::asin(1.); static constexpr double h = std::sqrt(.1); static constexpr double p = std::pow(1.3,-0.75); }; int main() { } 上面使用的标准库函数都不是constexpr函数 ,我们可以在C ++ 11标准 草案和C ++ 14标准草案 7.1.5 […]

int a = {1,2,}; 允许使用奇怪的逗号。 任何特定的原因?

也许我不是来自这个星球,但在我看来,以下应该是一个语法错误: int a[] = {1,2,}; //extra comma in the end 但事实并非如此。 当在Visual Studio上编译这个代码时,我感到很惊讶,但是我已经学会了不要信任MSVC编译器,所以我检查了这个标准,这也是标准所允许的。 如果你不相信我,你可以看到8.5.1的语法规则。 为什么这是允许的? 这可能是一个愚蠢的无用的问题,但我想让你明白我为什么问。 如果这是一个通用语法规则的子情况,我会理解 – 他们决定不要使一般语法更难,只是在初始化列表的末尾不允许多余的逗号。 但不,额外的逗号是明确允许的。 例如,不允许在函数调用参数列表的末尾有一个冗余的逗号(当函数采用… ), 这是正常的 。 那么,这个多余的逗号是明确允许的吗?

C ++ 11引入了标准化的内存模型。 这是什么意思? 那么如何影响C ++编程呢?

C ++ 11引入了标准化的内存模型,但究竟是什么意思呢? 那么如何影响C ++编程呢? 香草萨特在这里说, 内存模型意味着C ++代码现在有一个标准化的库来调用,不pipe编译器是谁做的,在哪个平台上运行。 有一个标准的方法来控制不同的线程如何与处理器的内存交谈。 Sutter说:“当你谈论的是跨标准的不同核心进行拆分时,我们正在谈论内存模型。我们将会优化它,而不会破坏人们在代码中所做的下列假设。 那么,我可以记住这个在线类似的段落(因为我已经有自己的记忆模型,自诞生以来:P),甚至可以回答别人提出的问题,但说实话,我不完全明白这一点。 所以,我基本上想知道的是,C ++程序员甚至在之前就开发了multithreading应用程序,所以如果是POSIX线程,Windows线程或者C ++ 11线程,它又有什么关系呢? 有什么好处? 我想了解低级细节。 我也感觉到C ++ 11内存模型与C ++ 11multithreading支持有某种联系,因为我经常将这两者结合在一起。 如果是这样,究竟是如何? 他们为什么要相关? 因为我不知道multithreading的内部工作原理,以及一般的内存模型意味着什么,所以请帮助我理解这些概念。 🙂

对multidimensional array的一维访问:定义明确的C?

我想我们都同意,通过以一维方式解引用其第一个元素(可能是偏移量)的指针来访问一个真正的multidimensional array被认为是惯用的C,例如: void clearBottomRightElement(int *array, int M, int N) { array[M*N-1] = 0; // Pretend the array is one-dimensional } int mtx[5][3]; … clearBottomRightElement(&mtx[0][0], 5, 3); 然而,在我的语言律师需要说服,这实际上是明确的C! 尤其是: 标准是否保证编译器不会在例如mtx[0][2]和mtx[1][0]之间填充内容? 通常,索引数组的末尾(除了末尾之外)是未定义的(C99,6.5.6 / 8)。 所以下面显然是不确定的: struct { int row[3]; // The object in question is an int[3] int other[10]; } foo; int *p = &foo.row[7]; // ERROR: […]

通过C ++标准,通过下标:合法的方式来获取一个最后一个数组元素的地址?

我已经看到它现在断言了几次,下面的代码是不允许的C + +标准: int array[5]; int *array_begin = &array[0]; int *array_end = &array[5]; 在这种情况下是否是&array[5]合法的C ++代码? 如果可能的话,我想要一个参考标准的答案。 知道它是否符合C标准也是有趣的。 如果它不是标准的C ++,那么为什么决定将它与array + 5或&array[4] + 1区别开来呢?