巧妙破解C++代码的邪恶样本

Ale*_*x B 39 c++

我需要一些糟糕的C++代码示例来说明违反良好做法的行为.我想提出我自己的例子,但是我很难想出一些没有做作的例子,而且陷阱不是很明显(它比看起来更难).

例子如下:

  1. 不为具有std::auto_ptr成员的类定义复制构造函数,并使用std::auto_ptr具有前向声明的类的成员.
  2. 从构造函数或析构函数(直接或间接)调用虚函数.
  3. 重载模板功能.
  4. 循环引用boost::shared_ptr.
  5. 切片.
  6. 从C回调中抛出异常(直接或间接).
  7. 相等的浮点比较.
  8. 具有原始指针成员的构造函数的异常安全性.
  9. 从析构函数中抛出.
  10. 在不同体系结构上编译时的整数溢出(size_t和的不匹配int).
  11. 使容器迭代器无效.

......或者你能想到的任何其他邪恶的东西.

我很欣赏对现有资源或一两个样本的一些指示.

In *_*ico 35

最令人烦恼的解析是C++解析这样的事情的一种令人惊讶的违反直觉的结果:

// 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
Run Code Online (Sandbox Code Playgroud)

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

  • 每次看到它我都会感到惊讶.反模式的问题在于你*不要一直使用它们,因此它们很容易被遗忘.您可能已经建立了避免问题的编码习惯,但这并不意味着您将在某些代码中轻松发现问题. (5认同)

Pal*_*mik 16

#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();
}
Run Code Online (Sandbox Code Playgroud)

输出是:

A's foo!
A's foo!
B's foo!
Run Code Online (Sandbox Code Playgroud)

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

  • 哦,亲爱的,const-ness上的虚函数重载.好的事情gcc有一个警告:`-Woverloaded-virtual`. (8认同)

In *_*ico 13

非异常安全的代码可能以对代码读者不明显的方式失败:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 例外情况非常糟糕 (2认同)

Lee*_*Lee 8

这一个今晚早些时候出现了.正如@ Billy ONeal在该帖子上指出的那样,eof()如果在流上发生错误,循环输入流(仅检查)会导致无限循环. good()应该用来代替.

坏:

while( !cin.eof() ) {
   getline(cin, input);
}
Run Code Online (Sandbox Code Playgroud)

好:

while( cin.good() ) {
   getline(cin, input);
}
Run Code Online (Sandbox Code Playgroud)

[来源:@James McNellis]

优秀:

while (std::getline(std::cin, input)) {
}
Run Code Online (Sandbox Code Playgroud)

  • 其次是:**优秀:**`while(std :: getline(std :: cin,input)){}` (9认同)

Dan*_*Dan 7

重载赋值运算符但未正确处理自赋值.


Nei*_*l G 7

您认为该计划将如何打印?

#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;
    b.f(true);
    b.f(1);
    A* a = &b;
    a->f(true);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

答:b,b,a!第一次打印输出很明显.第二个是b因为定义B::f(bool)隐藏了定义A::f(int).第三个是a因为重载解析发生在静态类型上.

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


Jam*_*lis 5

大多数C++程序员都不太了解Argument-Dependent Lookup(ADL,也称为Koenig查找),并且可能会导致一些非常不寻常的结果,尤其是与模板结合使用时.

我在回答ADL的哪些陷阱时讨论了ADL的一个主要缺陷


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

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