Package: libstdc++6-4.7-dev
Version: 4.7.2-5
Severity: important

Hello.

std::set<>::operator== uses operator== to compare elements instead of functor, 
specified in template parameters.
This makes imposible to compare sets of elements, which requires custom compare 
operator.
Minimal code example, which represents this wrong behaviour, is attached.

std::set<>::operator== uses underlying _Rb_tree container's operator== 
(stl_set.h:706),
which uses std::equal (stl_tree.h:867) to compare content by specifying 
iterators range.
std::equal, in turn, uses operator== to compare elements (stl_algobase.h:791).



-- System Information:
Debian Release: 7.4
  APT prefers stable
  APT policy: (500, 'stable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 3.2.0-4-amd64 (SMP w/4 CPU cores)
Locale: LANG=ru_RU.UTF-8, LC_CTYPE=ru_RU.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages libstdc++6-4.7-dev depends on:
ii  g++-4.7       4.7.2-5
ii  gcc-4.7-base  4.7.2-5
ii  libc6-dev     2.13-38+deb7u1
ii  libstdc++6    4.7.2-5

libstdc++6-4.7-dev recommends no packages.

Versions of packages libstdc++6-4.7-dev suggests:
pn  libstdc++6-4.7-doc  <none>

-- no debconf information
#include <set>
#include <iostream>
#include <memory>

template <
    class C,
    class PtrType = std::shared_ptr<C>,
    class Compare = std::less<C>
>
class CompareByValue {
    public:
        CompareByValue(): cmp() {}
        inline bool operator()(const PtrType& _1, const PtrType& _2) const {
            return _1 ? (_2 && cmp(*_1, *_2)) : bool(_2);
        }
    private:
        Compare cmp;
};

// Simple class with operator<.
class A {
    public:
        A(const std::size_t i_): i(i_) {}
        bool operator<(const A& other) const {return i < other.i;}
        std::size_t getI() const {return i;}
    private:
        const std::size_t i;
};

std::ostream& operator<<(std::ostream& stream, const A& c) {
    return stream << c.getI();
}

int main(int, char**) {
    typedef std::set<std::shared_ptr<A>, CompareByValue<A> > Set;
    using std::make_shared;
    
    // Initializing containers
    Set s0{make_shared<A>(1), make_shared<A>(2), make_shared<A>(3)};
    Set s1{make_shared<A>(1), make_shared<A>(2), make_shared<A>(3)};

    // Print containers content
    for (const auto& s : {s0, s1}) {
        for (const auto i : s)
            std::cout << *i << " ";
        std::cout << std::endl;
    }

    // Manually compare elements using CompareByValue<> and print results.
    CompareByValue<A> cmp;
    for (auto i0 = s0.begin(), i1 = s1.begin(); i0 != s0.end(); ++i0, ++i1) {
        std::cout << (!(cmp(*i0, *i1) || cmp(*i0, *i1))) << " ";
    }
    std::cout << std::endl;

    // Comparing containers using std::set<>::operator== ...Oops!
    std::cout << std::boolalpha << (s0 == s1) << std::endl;
}

Reply via email to