Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2004-01-22 14:24:11


On Jan 22, 2004, at 12:30 PM, David Abrahams wrote:

>
> The documentation says: "If types T1 and T2 are the same type, then
> there is only one version of the single-argument constructor, and this
> constructor initialises both values in the pair to the passed value."
>
> There is no indication that only one object of type T1 will actually
> ever be created when T1 == T2 and are empty, even though that is in
> fact the case. This violates a reasonable expectation (given by the
> standard) that two objects of the same type will have distinct
> addresses. The difference *is* detectable by the user.

Agreed there is a bug. Here's a quick and dirty test case:

#include <iostream>
#include <boost/compressed_pair.hpp>

struct A
{
     A() {std::cout << "A()\n";}
     A(const A&) {std::cout << "A(const A&)\n";}
     ~A() {std::cout << "~A()\n";}
     A& operator=(const A&) {std::cout << "A()::op=\n";return *this;}
};

int main()
{
// using Metrowerks::compressed_pair;
     using boost::compressed_pair;
     std::cout << "---\n";
     {
     compressed_pair<A, A> p1;
     }
     std::cout << "---\n";
     {
     compressed_pair<A, A> p2(A());
     }
     std::cout << "---\n";
     {
     compressed_pair<A, A> p3(A(), A());
     }
     std::cout << "---\n";
     std::cout << "sizeof(compressed_pair<A, A>) = "
               << sizeof(compressed_pair<A, A>) << '\n';
}

On my system this is printing out:

---
A()
~A()
---
A()
A(const A&)
~A()
~A()
---
A()
A()
A(const A&)
~A()
~A()
~A()
---
sizeof(compressed_pair<A, A>) = 1
Imho, the single argument constructor should fail to compile since what 
it does is far from obvious.  So after removing the middle test, I 
recommend this:
---
A()
A()
~A()
~A()
---
A()
A()
A(const A&)
A(const A&)
~A()
~A()
~A()
~A()
---
sizeof(compressed_pair<A, A>) = 1
which is how Metrowerks::compressed_pair behaves.
In the boost case, if you do nothing but neglect to run the single 
argument constructor, and if you give A a data member, then it now 
prints out the right sequence of ctors and dtors.  Having behavior 
change (beyond sizeof) based on whether or not A has a data member is 
very scary!  Constructors and destructors could have side effects, even 
for empty types.  compressed_pair should only optimize storage and not 
the number of objects created.
-Howard

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk