微妙破碎的C ++代码的邪恶的样本

我需要一些不好的C ++代码样本来说明违反良好做法的情况。 我想拿出我自己的例子,但是我很难提出一些没有人为的例子,而陷阱并不明显 (比看起来更难)。

例子会是这样的:

  1. 不使用std::auto_ptr成员为类定义复制构造函数,而是使用具有前向声明类的std::auto_ptr成员。
  2. 从构造函数或析构函数(直接或间接)调用虚函数。
  3. 重载模板函数。
  4. 循环引用与boost::shared_ptr
  5. 切片。
  6. 从Ccallback(直接或间接)抛出exception。
  7. 浮点比较平等。
  8. 具有原始指针成员的构造函数的exception安全性
  9. 从析构者投掷。
  10. 在不同的体系结构上编译时会发生整数溢出( size_tint不匹配)。
  11. 使容器迭代器无效。

…或任何其他可以想到的邪恶的东西。

我会欣赏一些指向现有资源,或一两个样本。

最令人头痛的parsing是C ++parsing这样的事情的一个令人惊讶的违反直觉的结果:

 // Declares a function called "myVector" that returns a std::vector<float>. std::vector<float> myVector(); // Does NOT declare an instance of std::vector<float> called "myVector" // Declares a function called "foo" that returns a Foo and accepts an unnamed // parameter of type Bar. Foo foo(Bar()); // Does NOT create an instance of Foo called "foo" nor creates a Bar temporary // Declares a function called "myVector" that takes two parameters, the first named // "str" and the second unnamed, both of type std::istream_iterator<int>. std::vector<float> myVector( std::istream_iterator<int>(str), std::istream_iterator<int>() ); // Does NOT create an instance of `std::vector<float>` named "myVector" while copying // in elements from a range of iterators 

这对任何不熟悉这种特殊语言的人都会感到惊讶(当我开始学习C ++时,包括我自己在内)。

 #include <iostream> class Base { public: virtual void foo() const { std::cout << "A's foo!" << std::endl; } }; class Derived : public Base { public: void foo() { std::cout << "B's foo!" << std::endl; } }; int main() { Base* o1 = new Base(); Base* o2 = new Derived(); Derived* o3 = new Derived(); o1->foo(); o2->foo(); o3->foo(); } 

输出是:

 A's foo! A's foo! B's foo! 

不知道它是否有名字,但肯定是邪恶的! :P

不是exception安全的代码可能会以代码读者不明显的方式失败:

 // Order of invocation is undefined in this context according to the C++ standard. // It's possible to leak a Foo or a Bar depending on the order of evaluation if one // of the new statements throws an exception before their auto_ptrs can "own" it accept_two_ptrs(std::auto_ptr<Foo>(new Foo), std::auto_ptr<Bar>(new Bar)); void MyClass::InvokeCallback(CallbackType cb) { Foo* resource = new Foo; cb(resource); // If cb throws an exception, resource leaks delete resource; } 

这个今天早些时候出现了 。 正如@Billy ONeal在那篇文章中指出的那样,在inputstream上循环,只检查eof() ,如果在stream上发生错误,会导致无限循环。 应该用good()来代替。

坏:

 while( !cin.eof() ) { getline(cin, input); } 

好:

 while( cin.good() ) { getline(cin, input); } 

[信用:@詹姆斯McNellis]

优秀:

 while (std::getline(std::cin, input)) { } 

重载赋值运算符,但不能正确处理自赋值 。

你认为该计划将打印什么?

 #include <iostream> using namespace std; struct A { void f(int) { cout << "a" << endl; } }; struct B: public A { void f(bool) { cout << "b" << endl; } }; int main() { B b; bf(true); bf(1); A* a = &b; a->f(true); return 0; } 

答: bba ! 第一个打印输出是显而易见的。 第二个是b因为B::f(bool)的定义隐藏了A::f(int)的定义。 第三个是因为重载parsing发生在静态types上。

(来源:本周大师,但我找不到这篇文章。)

参数依赖查找(ADL,也称为Koenig查找)不是大多数C ++程序员理解的,可能会导致一些非常不寻常的结果,尤其是当与模板结合使用时。

我讨论了ADL的一个主要缺陷,回答ADL的缺陷是什么?


重载分辨率涉及很多复杂性。 当在命名空间范围使用指令时,经常出现问题,特别是using namespace std ,因为该名称空间具有大量具有通用名称的实体。

下面是using namespace std导致问题的两个更近的例子:

  • 距离计算错误在c + +
  • 为什么没有积极的条件显示在这个asbolute程序

这一个,恕我直言,也是棘手的:

 class Base { int _value; public: Base() { _value = g(); } virtual int f() = 0; int g() { return f(); } }; class Derived: Base { public: Derived(): Base() { /* init Derived */ } int f() { /* implementation */ } } 

你的代码会因为没有实现纯虚f()而崩溃。 显而易见的原因是Derived在构造函数中还没有完成,所以你最终会调用虚f()并且不会被编译器检测到(通常,编译器会抱怨如果在构造函数中调用纯虚函数) 。

无论如何,如果你有复杂的构造函数调用其他成员函数,并且没有适当的unit testing,可能会发生虚拟纯调用。