简体   繁体   中英

“CopyConstructible” requirement for C++ stl container element

Regarding to the requirement for C++ stl container element, the standard says: the element type should be CopyConstructible, and there is a table for CopyConstructible requirements. Also by various books (Josuttis, etc.), the generated copy should be "equivalent to" the source.

I think I need some clarity here. What is exactly "equivalent to"? Also I am a bit confused with the relation between the "CopyConstructible" and the "deep/shallow copy". In general, a copy constructor is either shallow copy or deep copy. So which one applies to the "CopyConstructible", and which does not?

Thanks for any comments!

Deep or shallow copy both work. For instance, shared_ptr always does a shallow copy (with some extra reference counting stuff), and you can use them in containers just fine. It depends on the semantics of copy-operation.

Equivalent means your program should not depend on whether it works with the original or with the copy.

If you put something into a container, when you retrieve it you will get something that is equivalent to what you put in. So long as that is meaningful for your objects then you will get out something useful from the container.

Whether that is a shallow or deep copy depends on the semantics that you want for your object type. Your object might be pointer-like, handle-like or perhaps container like. It might contain some mutable cache data that you may or may not choose to duplicate on a copy operation.

So long as your copy constructor is accessible and does what you need it to do to preserve the semantics of your object type then you satisfy the CopyConstructible requirement.

In general, STL containers may copy your elements around at some stage, during some kinds of operations or algorithms, so the litmus test is:

Element original(....);  // construct this awesome object
original.this_and_that();  // do stuff to it until the value is perfect...

Element another(original);

Could you use another happily instead of original ?

That's effectively what the CopyConstructible requirement's saying: you better be able to have this copied into another object and still be happy with the result. It's not a draconian restriction - you just need to think it through and write your copy constructor correspondingly.

But, it's significant in that some operations like find() may use == to compare elements (for other containers, it may be '<'), so if a side-effect of being copied is that you can't compare elements meaningfully, then your find s et al may stop working - think that through too, (The Standard says for containers. "== is an equivalence relation" (23.1-5).)

Thinking that "a copy constructor performs either a deep or a shallow copy" is slightly limiting, and something of a red herring.

Whilst it's true that, depending on what your object stores as members, you may need to do some deep copying in order to gain equivalence, as far as the type's interface is concerned, it doesn't really matter how you performed the copy... as long as you did perform the copy and you ended up with an equivalent object.

And if A is equivalent to B , then for a properly-designed type, A==B .

The entire requirement is just saying: "the element type must be copyable". All the rest is down to usual common sense of writing a proper copy constructor.

There are a couple of different concepts being discussed here. CopyConstructible only requires that you can create a new element of that type using an existing element as the source from which to copy. It is unrelated to deep or shallow or even equivalence : the container does not care what you are doing while copying as long as it is allowed to perform that copy.

The second concept is the concept of equivalence , when you use an object in a container it will get copied, and the number of copies performed is unknown --the implementation might copy it just once to store it internally, or it might make multiple copies internally. What you want is to be able to extract the element from the container and use it as if it was the original object, here is where equivalence comes in: the n-th copy that you extract should be equivalent to the object that you inserted.

The concepts of deep and shallow copying are directly related to equivalence , depending on the domain that you are modeling, equivalence might require either shallow or deep copying, and depending on other constraints you might have to choose one or the other --as long as in your domain they are equivalent-- or there might even be intermediate options, where a partially deep copy is performed, or some members are not copied at all.

Related post: What is the difference between equality and equivalence?

Edited to make this a "non comment".

Equivalence means "equal for all intents and purposes". For example: 1.0001 and 1 are never equal, but under certain circumstances they are equivalent. This is the general answer.

What the books mean are that the copied objects must satisfy the strict weak ordering condition with the original object: copy < original == false && original < copy == false .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM