如何将指针的关系比较转换为错误?

Mar*_*ddy 10 c++ stl

我们多次遭到以下错误的困扰:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

void print(int* pn) { cout << *pn << " "; }

int main() {
    int* n1 = new int(1);
    int* n2 = new int(2);
    int* n3 = new int(3);

    vector<int*> v;
    v.push_back(n1);
    v.push_back(n2);
    v.push_back(n3);

    sort(v.begin(), v.end());   // Here be dragons!

    for_each(v.begin(), v.end(), print);
    cout << endl;
    delete n1; delete n2; delete n3;
}
Run Code Online (Sandbox Code Playgroud)

问题是std :: sort比较整数指针而不是整数,这不是程序员想要的.更糟糕的是,输出可能看起来是正确的和确定的(考虑新的或在堆栈上分配的地址的顺序).根问题是sort最终调用operator <for T,当T是指针类型时,这很少是个好主意.

有没有办法防止这种情况或者至少得到编译器警告?例如,有没有办法创建一个自定义版本的std :: sort,当T是指针时需要比较函数?

Cog*_*eel 12

IMO,程序员应该知道std::sort假设容器存储值.如果您需要不同的行为进行比较,那么您需要提供比较功能.例如(未经测试):

template<typename T>
inline bool deref_compare(T* t1, T* t2) { return *t1 < *t2; }

//...

std::sort(v.begin(), v.end(), deref_compare<int>);
Run Code Online (Sandbox Code Playgroud)

编辑

FWIW,雅各布的回答最接近于直接完成你想要的东西.可能有一些方法可以进一步概括它.


Jac*_*cob 2

对于一般的指针,你可以这样做:

    #include <ctime>
    #include <vector>
    #include <cstdlib>
    #include <algorithm>
    #include <functional>
    #include <type_traits>

    namespace util {
        struct sort_pointers {
            bool operator() ( int *a, int *b ) {
                return *a < *b;
            }
        };

        template <typename T, bool is_pointer = !std::tr1::is_pointer<T>::value>
        struct sort_helper {
            typedef std::less<T> wont_compare_pointers;
        };

        template <typename T>
        struct sort_helper<T,false> {
        };

        template <typename Iterator>
        void sort( Iterator start, Iterator end )
        {
            std::sort( start,
                       end,
                       sort_helper
                       <
                            typename Iterator::value_type
                       >::wont_compare_pointers() );
        }

        template <typename Iterator, class Func>
        void sort( Iterator start, Iterator end, Func f ) {
            std::sort( start, end, f );
        }
    }

    int main() {
        std::vector<int> v1;
        std::vector<int*> v2;
        srand(time(0));

        for( int i = 0; i < 10; ++i ) {
            v1.push_back(rand());
        }

        util::sort( v1.begin(), v1.end() );

        for( int i = 0; i < 10; ++i ) {
            v2.push_back(&v1[i]);
        }

        /* util::sort( v2.begin(), v2.end() ); */ //fails.
        util::sort( v2.begin(), v2.end(), util::sort_pointers() );

        return 0;
    }
Run Code Online (Sandbox Code Playgroud)

std::tr1::is_pointer这正是 Visual Studio 2008 中的名称,但我认为 Boost 也有一个,较新的编译可能会将其提供为std::is_pointer. 我确信有人能够编写一个更漂亮的解决方案,但这似乎可行。

但我必须说,我同意齿轮,没有理由这样做,程序员应该能够看到这是否会成为问题并采取相应的行动。

添加:

我认为您可以更概括化它,自动选择一个函子来取消引用指针并比较值:

namespace util {
    template <typename T>
    struct sort_pointers {
        bool operator() ( T a, T b ) {
            return *a < *b;
        }
    };

    template <typename T, bool is_pointer = !std::tr1::is_pointer<T>::value>
    struct sort_helper {
        typedef std::less<T> compare;
    };

    template <typename T>
    struct sort_helper<T,false> {
        typedef sort_pointers<T> compare;
    };

    template <typename Iterator>
    void sort( Iterator start, Iterator end )
    {
        std::sort( start,
                   end,
                   sort_helper
                   <
                        typename Iterator::value_type
                   >::compare() );
    }
}
Run Code Online (Sandbox Code Playgroud)

这样你就不必考虑是否向它提供比较指针,它会自动被排序。