Class containing auto_ptr stored in vector

前端 未结 5 904
小蘑菇
小蘑菇 2021-01-21 05:42

In an answer to Is it safe to store objects of a class which has an std::auto_ptr as its member variable in std::vector? I stated that a class that contained an auto_ptr could

相关标签:
5条回答
  • 2021-01-21 06:15

    Trying to put the list of places together that makes the example undefined behavior.

    #include <memory>
    #include <vector>
    using namespace std;
    
    struct Z {};
    
    struct A {
    
        A( Z z ) 
            : p( new Z(z) ) {} 
    
        A( const A & a ) 
            : p( a.p.get() ? new Z( *a.p.get()) : 0 ) {}
    
        // no assigment op or dtor defined by intent
    
        auto_ptr <Z> p;
    };
    
    int main() {
        vector <A> av;  
        ...
    }
    

    I will examine the lines up to the one where you instantiate the vector with your type A. The Standard has to say

    In 23.1/3:

    The type of objects stored in these components must meet the requirements of CopyConstructible types (20.1.3), and the additional requirements of Assignable types.

    In 23.1/4 (emphasis mine):

    In Table 64, T is the type used to instantiate the container, t is a value of T, and u is a value of (possibly const) T.

    +-----------+---------------+---------------------+
    |expression |return type    |postcondition        |
    +-----------+---------------+---------------------+
    |t = u      |T&             |t is equivalent to u |
    +-----------+---------------+---------------------+
    

    Table 64

    In 12.8/10:

    If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. The implicitly-declared copy assignment operator for a class X will have the form

    X& X::operator=(const X&)
    

    if

    • each direct base class B of X has a copy assignment operator whose parameter is of type const B&, const volatile B& or B, and
    • for all the nonstatic data members of X that are of a class type M (or array thereof), each such class type has a copy assignment operator whose parameter is of type const M&, const volatile M& or M.

    Otherwise, the implicitly declared copy assignment operator will have the form

    X& X::operator=(X&)
    

    (Note the last and second last sentence)

    In 17.4.3.6/1 and /2:

    In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ Standard Library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.

    In particular, the effects are undefined in the following cases:

    • for types used as template arguments when instantiating a template component, if the operations on the type do not implement the semantics of the applicable Requirements subclause (20.1.5, 23.1, 24.1, 26.1). Operations on such types can report a failure by throwing an exception unless otherwise specified.

    Now, if you look at the specification of auto_ptr you will note it has a copy-assignment operator that takes a non-const auto_ptr. Thus, the implicitly declared copy assignment operator of your class will also take a non-const type as its parameter. If you read the above places carefully, you will see how it says that instantiating a vector with your type as written is undefined behavior.

    0 讨论(0)
  • 2021-01-21 06:15

    What about the following?

    cout << av[ 0 ] << endl;
    

    Also, conceptually, a copy should leave the item copied from unchanged. This is being violated in your implementation.

    (It is quite another thing that your original code compiles fine with g++ -pedantic ... and Comeau but not VS2005.)

    0 讨论(0)
  • 2021-01-21 06:21

    I don't think it's necessarily the case that the above code will even compile. Surely the implementor of std::vector is at liberty to require an assignment operator to be available, from const A&?

    And having just tried it, it doesn't compile on Visual Studio C++ 2008 Service Pack 1:

    binary '=' : no operator found which takes a right-hand operand of type 'const A' (or there is no acceptable conversion)

    My guess is that, on the guidance of Herb Sutter, the container classes in VC++ make every effort to impose the standard requirements on their type parameters, specifically to make it hard to use auto_ptr with them. They may have overstepped the boundaries set by the standard of course, but I seem to remember it mandating true assignment as well as true copy construction.

    It does compile in g++ 3.4.5, however.

    0 讨论(0)
  • 2021-01-21 06:31

    Since the regular auto_ptr semantic could suggests that the ownership is passed during the copying, I would rather use here boost::scoped_ptr. Of course the assignment operator is missing.

    0 讨论(0)
  • 2021-01-21 06:32

    Objects stored in containers are required to be "CopyConstructable" as well as "Assignable" (C++2008 23.1/3).

    Your class tries to deal with the CopyConstructable requirement (though I'd argue it still doesn't meet it - I edited that argument out since it's not required and because it's arguable I suppose), but it doesn't deal with the Assignable requirement. To be Assignable (C++2008 23.1/4), the following must be true where t is a value of T and u is a value of (possibly const) T:

    t = u returns a T& and t is equivalent to u

    The standard also says in a note (20.4.5/3): "auto_ptr does not meet the CopyConstructible and Assignable requirements for Standard Library container elements and thus instantiating a Standard Library container with an auto_ptr results in undefined behavior."

    Since you don't declare or define an assignment operator, an implicit one will be provided that uses the auto_ptr's assignment operator, which definitely makes t not equivalent to u, not to mention that it won't work at all for "const T u" values (which is what Earwicker's answer points out - I'm just pointing out the exact portion(s) of the standard).

    0 讨论(0)
提交回复
热议问题