小编Mar*_*wen的帖子

在C++ 11中,`i + = ++ i + 1`是否表现出未定义的行为?

在我阅读的过程中出现了这个问题(答案) 那么为什么i = ++ i + 1在C++ 11中定义明确?

我认为,微妙的解释是(1)表达式++i返回一个左值但是+将prvalues作为操作数,因此必须执行从左值到右值的转换; 这涉及获得该左值的当前值(而不是旧值的一个以上i),因此必须在增量的副作用(即更新)之后进行排序i(2)赋值的LHS也是左值,所以它的价值评估不涉及取得当前价值i; 虽然这个值计算在RHS的值计算中是不可测的,但这没有问题.(3)赋值本身的值计算涉及更新i(再次),但是在其RHS的值计算之后排序,因此在变换之后更新到i; 没问题.

很好,所以那里没有UB.现在我的问题是如果将分配运算符更改=+=(或类似的运算符).

表达式的评估是否会i += ++i + 1导致未定义的行为?

在我看来,标准似乎在这里自相矛盾.由于LHS +=仍然是左值(并且其RHS仍然是prvalue),所以与上述相同的推理适用于(1)和(2); 在操作数的评估中没有未定义的行为+=.至于(3),复合赋值的运算+=(更确切地说是该运算的副作用;它的值计算,如果需要,在任何情况下在其副作用之后排序)现在必须同时获取当前值i,然后(显然在它之后排序,即使标准没有明确说明,或者对这些运算符的评估总是会调用未定义的行为)添加RHS并将结果存回i.如果它们的副作用没有排序,这两个操作都会给出未定义的行为++,但正如上面所论述的那样(在给出运算符的RHS ++的值计算之前对其进行排序的副作用,该计算值在计算之前排序.该复合转让的操作),情况并非如此.++=

但另一方面,标准也表示E += F相当于E = E + F,除了(左值)E仅被评估一次.现在在我们的例子中,作为左值的i(E …

c++ undefined-behavior language-lawyer c++11

47
推荐指数
3
解决办法
3295
查看次数

如何显式调用名称空间限定的析构函数?

我很惊讶以下简单代码无法编译(使用gcc,版本4.8.1)

#include <string>
void test()
{
  std::string* p = new std::string("Destruct me");
  p->std::~string();
}
Run Code Online (Sandbox Code Playgroud)

它说:错误:'〜'之前的范围'std'不是类名.然而,阅读标准,我会说语法说它应该是" postfix-expresssion - > pseudo-constructor-name ",其中伪构造函数名称可以是" nested-name-specifier ~ type-name "形式,和nested-name-specifier可以是" identifier ::".

离开"std ::"会引起一个抱怨,即在左边的paren之前预计有一个类名,并且在倾向之后将它放在"::"之前预期类名的投诉之后.经过一些尝试后,我发现它会在编写时编译p->std::string::~string();(但不会在编写时编译p->std::string::~std::string();).但是使用自己的类型名称来限定析构函数并不是一个中立的操作; 我从标准的12.4:13中的示例中收集(但奇怪的是不是来自规范性文本),这会强制调用精确静态(基类)类的析构函数,而不是作为(最大派生的)虚函数指向的实际对象的类型.这没有区别,但在相似的情况下它会; 为什么语法会强制使用静态类型?

但是,使用clang而不是gcc,即使提到的变体也会出现语法错误.如果你在阅读错误信息时想要获得这种幽默,那么clang的错误信息会更有趣:因为p->std::string::~string();它给出了"'''之后的类名称命名析构函数"(所以它确实如此) ;人们想知道哪种类名称不会被命名为析构函数(如果以波浪号为前缀),并且在我的初始试验中p->std::~string()它反驳"合格的成员访问是指名称空间'std'中的成员"(再次想知道这有什么问题) ;实际上被调用的析构函数位于命名空间"std"中.我已经尝试了所有8个合理的组合(在代字号之前的std ::和/或string ::和/或之后的/或std ::)并且它们都没有用clang编译.

即使是使用clang,我也可以编译它using std::string;.但我发现很奇怪的是,在标准中我没有发现这样的声明在这种情况下是必要的.事实上,我找不到解决调用命名空间限定类的析构函数的问题. .我错过了一些明显的东西吗

作为最后一点,我想补充说,在调用析构函数时,根本不需要使用命名空间限定.由于这是一个来自一个良好指定对象的成员访问(这里*p)不应该依赖于参数的查找使显式限定命名空间不必要吗?

c++ standards g++ clang++

25
推荐指数
2
解决办法
3820
查看次数

具有从未实际执行的未定义行为的表达式是否会导致程序错误?

在关于未定义行为(UB)的许多讨论中,已经提出了这样的观点:在程序中存在任何具有UB的任何构造的程序都要求一致的实现做任何事情(包括什么都没有).我的问题是,即使在UB与代码执行相关联的情况下,是否应该采取这种方式,而标准中规定的行为(否则)规定不应执行相关代码(这可能是对于程序的特定输入;它可能在编译时不可判定).

更加非正式地说,UB的气味是否要求一致的实现来决定整个程序发臭,并且拒绝正确执行甚至行为完全明确定义的程序部分.一个示例程序将是

#include <iostream>

int main()
{
    int n = 0;
    if (false)
      n=n++;   // Undefined behaviour if it gets executed, which it doesn't
    std::cout << "Hi there.\n";
}
Run Code Online (Sandbox Code Playgroud)

为清楚起见,我假设程序格式正确(因此特别是UB与预处理无关).事实上,我愿意将UB限制为与"评估"相关联,而"评估"显然不是编译时实体.我认为,与给出的例子相关的定义(重点是我的):

之前排序的是由单个线程(1.10)执行评估之间的不对称,传递,成对关系,这导致这些评估之间的部分顺序

在运算符的结果的值计算之前,对运算符的操作数的值计算进行排序.如果对标量对象的副作用相对于...或使用相同标量对象的值进行值计算未被排序,则行为未定义.

隐含地清楚的是,最后一句中的主语"副作用"和"价值计算"是"评价"的实例,因为这就是定义"之前排序"的关系.

我认为在上述程序中,标准规定不进行评价,以满足最后一句中的条件(相对于彼此和所描述的类型),并且该程序不具有UB; 这不是错误的.

换句话说,我确信我的标题问题的答案是否定的.但是,我会很感激其他人对此事的(动机)意见.

对于那些主张肯定答案的人来说,可能还有一个问题是,当编译错误的程序时,会强制重新格式化硬盘吗?

本网站上的一些相关指针:

c++ undefined-behavior language-lawyer

19
推荐指数
3
解决办法
1117
查看次数

使用常量数据成员或引用成员移动类的ctor

我有一些问题,了解何时以及是否调用移动构造函数或移动赋值运算符,特别是在具有常量数据成员的类的上下文中.考虑上课

template<typename T> class A {
  const*T const P ;   // constant data member
  explicit A(const*T p) : P(p) { std::cerr<<" ctor: P="<<P<<'\n'; }
  void test() const { std::cerr" test: P="<<P<<'\n'; }
  // move and copy constructors and assignment operators here
};
Run Code Online (Sandbox Code Playgroud)

和测试程序

class B {
  int X[100];
  A<B> get_a() const { return A<B>(this); }
};

int main() {
  B b;
  A<B> a = b.get_a();   // which operator/ctor is used for '=' here?
  a.test();
}
Run Code Online (Sandbox Code Playgroud)

那么编译的结果会有所不同,具体取决于为类中的移动构造函数和移动赋值运算符提供的定义A<>,还有编译器.

1在类中没有任何进一步的声明 …

c++ constructor move-semantics c++11

6
推荐指数
1
解决办法
705
查看次数

是否存在与`std :: move`具有相反效果的强制转换(或标准函数)

首先,这个问题是不是重复功能双到std ::移动?或者std :: move的反转是否存在?.我不是要问一种机制,以防止在原本会发生的情况下移动,而是复制; 相反,我正在询问一种机制,使rvalue被接受在一个将被绑定到可修改左值引用的位置.事实上,这std::move与发明的情况完全相反(即,在一个将被绑定到(可修改的)右值参考的位置上接受可修改的左值).

在我感兴趣的情况下,不会接受右值,因为上下文需要可修改的左值引用.由于某种原因,我不太明白但愿意接受,(可修改的)右值表达式将绑定到一个常量左值引用(不引入额外的临时值),但它不会绑定到可修改的左值引用( gcc给我的错误信息是"从'A'类型的右值'中'A&'类型的非const引用的无效初始化",而clang说"对类型'A'的非const左值引用不能绑定到临时的输入'A'';奇怪的是我无法让这些编译器中的任何一个承认有问题的表达式有'A &&'类型,即使该表达式实际上是static_cast<A&&>(...)单独引发错误的形式.我可以理解,通常不希望在需要可修改的左值引用的位置接受rvalue表达式,因为它意味着通过该左值引用完成的任何修改都将丢失,但正如调用std::move对编译器说的那样"我知道这是一个左值,它将被绑定到右值参考(参数),因此可能会被盗,但我知道我在做什么,这里没关系"我想在我的案例中说"我知道这是临时的,它将被绑定到一个可修改的左值引用(参数),因此通过左值引用所做的任何更改都会被忽略,但我知道我在做什么,这里没关系".

我可以通过从rvalue 初始化类型A 的命名对象,然后提供需要可修改左值引用的名称来解决问题.我不认为这有额外的运行时开销(无论如何都需要rvalue的临时开启),但是必须这样做在几个方面很尴尬:必须引入一个虚拟名称,可能只需引入一个复合语句保持声明,将产生rvalue的表达式与函数调用分开,它为其提供参数.我的问题是否可以在不引入虚拟名称的情况下完成:

  1. 是否有任何方法(例如使用强制转换)将类型A的rvalue表达式绑定到类型A的可修改左值引用并且不引入类型A的命名对象?
  2. 如果没有,这是一个刻意的选择吗?(如果是这样,为什么?)如果有,是否有类似于std::move标准提供的机制来促进它?

这是一个简化的插图,我需要这样的转换.我故意删除了A的特殊构造函数,以确保错误消息不涉及编译器决定引入的临时文件.当A&被替换时,所有错误都会消失const A&.

class A
{ int n;
public:
  A(int n) : n(n) {}
  A(const A&) = delete; // no copying
  A(const A&&) = delete; // no moving either
  int value() const { return n; }
};

int f(A& x) …
Run Code Online (Sandbox Code Playgroud)

c++ c++11

6
推荐指数
2
解决办法
780
查看次数

如何使用 SFINAE 限制输入迭代器的过载

许多容器类模板都有一个构造函数,它接受一个计数和一个样本元素作为参数,另一个构造函数接受一对输入迭代器。其他方法如insert表现出相同的模式。当模板使用整数类型实例化时,一个幼稚的实现会遇到麻烦,并且构造函数(或其他方法)使用一对整数调用:它们的类型相等,输入迭代器方法将给出有效的参数类型推导,但随后无法编译。

我正在寻找一种优雅的方式来指定输入迭代器方法只参与重载实际上是有效输入迭代器类型的(相等)参数类型,或者至少不参与整数类型。我的印象是 SFINAE 是要走的路(但很高兴被告知不同的方式),但是在阅读它时,坦率地说我不太了解规则,而且示例中提供的解决方案几乎不符合优雅.

作为附带限制,我希望我的代码能够与不完整的 C++11 支持的 gcc 4.6 兼容。值得注意的是,我想避免使用模板别名。这是我笨拙的尝试(裸露的骨头):

#include <iterator>
#include <type_traits>
#include <vector>

template <typename I>
  struct input_iter : public std::integral_constant<bool,
  not std::is_integral<I>::value
  and std::is_base_of
    <std::input_iterator_tag
    ,typename std::iterator_traits<I>::iterator_category
    >::value >
  {};

template<typename T>
  struct container
{
  container (size_t count, const T& init);
  template <typename InputIt,
            typename = typename std::enable_if<input_iter<InputIt>::value>::type >
    container (InputIt first,InputIt last);
};

typedef container<int> int_cont;

void f()
{ std::vector<int> v (5,3);
  int_cont a1 (3u,6); // first constructor
  int_cont a2 (3u,6); // first …
Run Code Online (Sandbox Code Playgroud)

c++ templates c++11

6
推荐指数
1
解决办法
1185
查看次数

如何优雅地从列表中剪掉不同长度的尾巴?

我对Python很新,这是一个相当基本的问题.

我有一个名单lst,并已在一些点计算的整数n0<=n<=len(lst),告诉我说,(在手的目的),我应该放弃最后n名单的元素.想到达到这个目的的说法是del lst[-n:]或者lst[-n:]=[](我发现在任何一种情况下0,在冒号之后添加不是一个好主意,因为零不被认为大-n于此设置).但是n==0,当列表完全清空时,两种变体都会失败.我真的应该在这里插入一个明确的零测试,或者弯腰写作

del lst[len(lst)-n:]
Run Code Online (Sandbox Code Playgroud)

还是有更优雅(可靠)的东西可以在这里完成?

python

5
推荐指数
1
解决办法
821
查看次数

为包含联合的结构定义 `swap` 方法;怎么做?

我正在调整一些 C++03 代码以利用 C++11 的新可能性,特别是在 C++11 方式中引入移动语义。但是我遇到了一个struct让我头疼的地方,因为它包含一个匿名联合。它具有全局形式

struct tree
{ // data of |tree|
  enum {tag0,tag1, tag2, ... } kind;
  union
  { type1 field1;
    type2 field2;
    ...
  };

  // constructors
  tree () : kind(tag0) {} // default, empty state
  tree (const& type1 x) : kind(tag1), field1(x) {} // variant 1
  tree (const& type2 x) : kind(tag2), field2(x) {} // variant 2
  ...
  ~tree(); // recursively clean up any branches

  // other methods of |tree|
  ...
}; // |struct …
Run Code Online (Sandbox Code Playgroud)

c++ swap unions c++11

5
推荐指数
1
解决办法
805
查看次数