Should an STL container avoid copying elements into themselves when the container is copied into itself?

冷暖自知 提交于 2019-12-03 01:21:43

The pre/post conditions of assignment of a container specified by the standard (quoting latest draft):

[tab:container.req]

r = a

Ensures: r == a.

This allows but does not mandate self assignment check.

interested if I should add a self-assignment check to the beginning of the assignment operator, or should I just copy the contained element into itself?

C++ Core Guidelines recommends not to do a self-assignment check in a user class if all of its members are self-assignment safe:

Enforcement (Simple) Assignment operators should not contain the pattern if (this == &a) return *this;???

It is for an efficiency reason. Self-assignments are unlikely to happen in practice. They are rare, and so it is better to avoid doing a self-assignment check in every operation. A self-assignment check probably makes the code faster in self-assignment case (very rare) and makes it slower in all other cases (more common).

Imagine you assign a million elements. In every assignment operation a self-assignment check is done. And it is most probably that it is done for nothing because none of the assignments is actually a self-assignment. And so we do a million useless checks.

If we skip doing a self-assignment check then nothing bad happens except that if self-assignment really happens then we do useless self-assignments of all members (that is sometimes slower than doing a single self-assignment check at the beginning of the assignment operator). But if your code does a million self-assignments it is a reason to reconsider your algorithm rather than to perform a self-assignment check in all of the operations.

However, self-assignment check still must be used for classes that are not self-assignment safe by default. The example is std::vector. The vector, that is being copied into, first has to delete the existing elements. But if the destination vector and source vector is the same object, then by deleting the elements in destination vector we also delete them in the source vector. And so it won't be possible to copy them after deletion. That is why libstdc++ does a self-assignment check for std::vector (though it is possible to implement std::vector without self-assignment check).

But it doesn't do it for std::variant for example. If you copy a variant into itself then the contained value will be copied into itself. See live example. Because copying it into itself is self-assignment safe (provided the contained value is self-assignment safe).

Thus, libstdc++ does a self-assignment check for std::vector (for providing self-assignment safety), and doesn't for std::variant (for efficiency).

[...] if I should add this checking to the beginning of the assignment operator [...] ?

You should, regardless whether std::vector, or other STL containers do that for you. Imagine a user that works with your library and does x = x, outside of STL containers scope.

Now to the STL container requirements - I believe the standard does not specify whether assignment is required to perform a check for being a self-assignment (went through the majority of Containers library section). This gives room for compiler optimisations and I believe that a decent compiler should perform such checks.

Checking this == &rhs is actually a pretty well-known idiom, and helps to be sure that you don't break anything by guaranteeing that lhs and rhs are different objects. So, this is valid and actually encouraged.

I don't know whether STL containers are required to do the check, though.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!