Container elements with const members

Discussion in 'C++' started by Nobody, Apr 21, 2004.

  1. Nobody

    Nobody Guest

    The requirement that STL container elements have to be assignable is causing
    me a problem.
    Consider a class X which contains both const and non-const data members:

    class X
    {
    public:
    X(const std::string &rStrId, int x) : m_strId(strId), m_x(x)
    {
    }

    private:
    X& operator=(const X &rhs); // not allowed
    X(const X& rhs); // not allowed

    const std::string m_strId;
    int m_x;
    };

    I know that because I have the data member, m_strId, declared as *const*, it
    means that I cannot assign to it. This was OK as I didn't need to and
    therefore made it private with no implementation.

    Then I decided that I needed to have an STL vector of Xs.

    X x(std::string("hello"), 43);
    std::vector<X > xVector;
    ....
    xVector.push_back(X(std::string("hello"), 43));

    I know too that when using STL containers the standard says that the
    contained objects must be copyable and assignable.

    This is my dilemma. If I don't supply an assignment operator for X or I make
    it private then it won't compile when I try to push an instance of X into
    the vector.

    I have considered the following options:

    1) Make the string non const and let the compiler generate the assignment
    operator. I don't want to do this as each instance of X is required to have
    a unique string identifier, m_strId, which will not change throughout the
    lifetime of the object.

    2) Provide an assignment operator that only assigns the non const int m_x.
    This would allow the possibility of assigning one X object to another and
    the result not being equal.

    Which is the best option of the two? Are there any other alternatives I
    haven't considered which are better?

    TIA

    RP
     
    Nobody, Apr 21, 2004
    #1
    1. Advertising

  2. Nobody

    Siemel Naran Guest

    "Nobody" <> wrote in message news:E4Bhc.3313

    > class X
    > {
    > public:
    > X(const std::string &rStrId, int x) : m_strId(strId), m_x(x)
    > {
    > }
    >
    > private:
    > X& operator=(const X &rhs); // not allowed
    > X(const X& rhs); // not allowed
    >
    > const std::string m_strId;


    > I know too that when using STL containers the standard says that the
    > contained objects must be copyable and assignable.


    > 1) Make the string non const and let the compiler generate the assignment
    > operator. I don't want to do this as each instance of X is required to

    have
    > a unique string identifier, m_strId, which will not change throughout the
    > lifetime of the object.


    Yes, your design should reflect your business requirements, not the
    technical requirements on STL containers.

    > 2) Provide an assignment operator that only assigns the non const int m_x.
    > This would allow the possibility of assigning one X object to another and
    > the result not being equal.


    Yes, this also violates your business requirement.

    > Which is the best option of the two? Are there any other alternatives I
    > haven't considered which are better?


    Use a container of pointers to X. Remember to delete the pointed to objects
    when the container goes out of scope.

    You could try smart pointers, like so:

    std::vector<boost::shared_ptr<X> > d_container;
     
    Siemel Naran, Apr 21, 2004
    #2
    1. Advertising

  3. On Wed, 21 Apr 2004, Nobody wrote:

    [snip]

    >class X
    >{
    >public:
    > X(const std::string &rStrId, int x) : m_strId(strId), m_x(x)
    > {
    > }
    >
    > private:
    > X& operator=(const X &rhs); // not allowed
    > X(const X& rhs); // not allowed
    >
    > const std::string m_strId;
    > int m_x;
    >};


    [snip]

    >X x(std::string("hello"), 43);
    >std::vector<X > xVector;
    >...
    > xVector.push_back(X(std::string("hello"), 43));
    >
    >I know too that when using STL containers the standard says that the
    >contained objects must be copyable and assignable.


    [snip]

    >I have considered the following options:
    >
    >1) Make the string non const and let the compiler generate the assignment
    >operator. I don't want to do this as each instance of X is required to have
    >a unique string identifier, m_strId, which will not change throughout the
    >lifetime of the object.
    >
    >2) Provide an assignment operator that only assigns the non const int m_x.
    >This would allow the possibility of assigning one X object to another and
    >the result not being equal.
    >
    >Which is the best option of the two?


    Neither option is correct if your code must guarantee that there is only
    one instance for any string identifier, and the same string identifier
    for a given object throughout the object's lifetime.

    >Are there any other alternatives I
    >haven't considered which are better?


    Yes, store pointers in the vector. For example:

    #include <vector>
    #include <string>

    class X
    {
    public:
    X(const std::string &rStrId, int x)
    : m_strId(rStrId), m_x(x)
    {}

    private:
    X& operator=(const X &rhs); //not allowed
    X(const X& rhs); //not allowed

    const std::string m_strId;
    int m_x;
    };

    class App
    {
    std::vector<X*> m_pvx;

    public:
    App()
    : m_pvx()
    {}

    ~App()
    {
    for (std::vector<X*>::iterator it = m_pvx.begin();
    it != m_pvx.end();
    ++it)
    delete *it;
    }

    void run()
    {
    m_pvx.push_back(new X(std::string("hello"), 43));
    }
    };

    int main()
    {
    App().run();
    }

    --
    Claudio Jolowicz
    http://www.doc.ic.ac.uk/~cj603
     
    Claudio Jolowicz, Apr 21, 2004
    #3
  4. "Claudio Jolowicz" <> wrote in message
    news:p...
    | On Wed, 21 Apr 2004, Nobody wrote:

    |
    | Yes, store pointers in the vector. For example:

    [snip]

    |
    | class App
    | {
    | std::vector<X*> m_pvx;

    ^^^^^^^^^^^^^^^^^^^^^^

    highly non-recommended. Use vector< shared_ptr<X> >.

    br

    Thorsten
     
    Thorsten Ottosen, Apr 22, 2004
    #4
  5. Nobody

    Siemel Naran Guest

    "Thorsten Ottosen" <> wrote in message
    news:408703bd$0$20662
    > "Claudio Jolowicz" <> wrote in message


    >> std::vector<X*> m_pvx;

    >
    > highly non-recommended. Use vector< shared_ptr<X> >.


    Highly non-recommended by who? I think Claudio's original solution is fine.
    It uses less memory than your version (a counted_ptr is about twice the size
    as a regular pointer, plus add memory for the actual integers), though
    granted this may sometimes pale in comparison to the sizeof(X).

    To save on the typing, it would be nice to generalize the idea to a template
    class pointer_container<T> that holds a container<T*>, and whose destructor
    deletes the items.
     
    Siemel Naran, Apr 22, 2004
    #5
  6. Nobody

    Dave Moore Guest

    "Siemel Naran" <> wrote in message news:<5NGhc.18257$>...

    > To save on the typing, it would be nice to generalize the idea to a template
    > class pointer_container<T> that holds a container<T*>, and whose destructor
    > deletes the items.


    Hmm .. aren't there ownership issues inherent to this idea? Who is to
    say that the elements in the container belong to it? Couldn't the
    pointer-elements have been initialized from already existing objects,
    for example the elements of another container<T*>? It seems to me
    that this would only really be useful in the context of the boost
    smart-pointers, where ownership is already clear, IOW

    shared_ptr_container<T> for container<shared_ptr<T> >, when the
    elements will be owned by the container and
    weak_ptr_container<T> for container<weak_ptr<T> > when they will not.

    I suppose you could do a similar thing without boost as:

    owned_ptr_container<T> // destructor deletes elements
    view_ptr_container<T> // destructor doesn't delete elements

    Dave Moore
     
    Dave Moore, Apr 22, 2004
    #6
  7. Nobody

    Siemel Naran Guest

    "Dave Moore" <> wrote in message
    > "Siemel Naran" <> wrote in message

    news:<5NGhc.18257

    > > To save on the typing, it would be nice to generalize the idea to a

    template
    > > class pointer_container<T> that holds a container<T*>, and whose

    destructor
    > > deletes the items.

    >
    > Hmm .. aren't there ownership issues inherent to this idea? Who is to
    > say that the elements in the container belong to it? Couldn't the
    > pointer-elements have been initialized from already existing objects,
    > for example the elements of another container<T*>? It seems to me
    > that this would only really be useful in the context of the boost
    > smart-pointers, where ownership is already clear, IOW


    Right, to make the intent clear we ought to name the container as
    owned_pointer_container or something like that. But my intent was to not
    use boost::shared_ptr in the implementation of my class.

    > shared_ptr_container<T> for container<shared_ptr<T> >, when the
    > elements will be owned by the container and
    > weak_ptr_container<T> for container<weak_ptr<T> > when they will not.
    >
    > I suppose you could do a similar thing without boost as:
    >
    > owned_ptr_container<T> // destructor deletes elements
    > view_ptr_container<T> // destructor doesn't delete elements


    Yes, those are good names.
     
    Siemel Naran, Apr 22, 2004
    #7
  8. Nobody

    MikeB Guest

    "Siemel Naran" <> wrote in message
    news:BEShc.10706$...

    > owned_pointer_container or something like that. But my intent was to not
    > use boost::shared_ptr in the implementation of my class.


    I'm a bit lost here. In your first reply to the OP, you suggested that he

    "...could try smart pointers, like so:
    std::vector<boost::shared_ptr<X> > d_container;"

    I assumed that in doing so you were actually recommending that he *should*
    try boost::shared_ptr.

    Rgds,
    MikeB
     
    MikeB, Apr 22, 2004
    #8
  9. Nobody

    Siemel Naran Guest

    "MikeB" <> wrote in message news:c698cf$ktn$1
    > "Siemel Naran" <> wrote in message


    > > owned_pointer_container or something like that. But my intent was to

    not
    > > use boost::shared_ptr in the implementation of my class.

    >
    > I'm a bit lost here. In your first reply to the OP, you suggested that he
    >
    > "...could try smart pointers, like so:
    > std::vector<boost::shared_ptr<X> > d_container;"
    >
    > I assumed that in doing so you were actually recommending that he *should*
    > try boost::shared_ptr.


    I gave 2 possibilities, one vector<boost::shared_ptr<T>> and the other
    essentially vector<T*>. The owned_pointer_container method is just
    vector<T*> with an interface to delete the internal items.
     
    Siemel Naran, Apr 23, 2004
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Rakesh Sinha
    Replies:
    4
    Views:
    1,863
    Rakesh Sinha
    Jan 13, 2005
  2. Replies:
    4
    Views:
    815
    Daniel T.
    Feb 16, 2006
  3. Javier
    Replies:
    2
    Views:
    585
    James Kanze
    Sep 4, 2007
  4. Hicham Mouline
    Replies:
    1
    Views:
    407
    Kai-Uwe Bux
    Apr 11, 2010
  5. Vladimir Menshakov
    Replies:
    1
    Views:
    371
Loading...

Share This Page