A fun small bug in the C ++ standard library

xiaoxiao2021-03-06  103

When you look at other people's code, an unexpectedly discovered a standard library (I don't know if there is any mention in the standard committee's C Standard lib.core issu file, whether it) is like this, the code is as follows: struct x {}; Ostream & Operator << (Ostream & Out, X & X / * bad habits * /) {^^^^ ---- # 1 non-const reference ... return out;} void use11 () {Vector

v; v.push_back (x ()); copy (v.begin (), v.end (), Ostream_IstRerator

(cout, "/ n"))))); // Compiling errors! } void use2 () {x x; cout << x;

}

According to semantics, USE1 and USE2 should be compiled, but the fact is that USE1 cannot be compiled. The reason is # 1, if X & Change is changed to X Const & Everything is good. Why is it? Look at the definition of ostream_iterator: one of the members is such ostream_iterator & operator = (const _tp & __value) {^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; // should go to the user's overloaded Operator << to ...} The top of the example (...) each iterates further to call this function, give the iterator point to the value, then This function is: * _ m_stream << __Value; actually equivalent to cout << __ value, output this value, is it wrong? Look at the type of parameter __value, is Const &, and the Operator << we overloaded only accepts the non-const reference, so you can't find a match. The key here is that the member Operator Operator Operator Operator Operator = for its parameters, the semantic-constine, regardless of whether it is Const.

There are two kinds: For users, the solution is to overrunate Operator <<, pay attention to the second parameter, it is best to write a const reference parameter, otherwise, "Copy (V.Begin (), v.end (), ostream_iterator

(COUT) "The call mode will be missing. This scorpion is still serious, at least you are still blocked, and another situation is more serious - through compiling but the result is can't touch, we Together with the original example: Ostream & Operator << (Ostream & Out, X * & PX) {... return out;} void use3 () {x * px = new x; cout

COPY Why print an address? Because the ostream has a member function to be a VOID * overload, a hidden type conversion has occurred. This error is more concealed compared to the previous mistake. It will appear when you want to run. For the library designer, this is a negligence, there is a simple solution to add an operator = member function for ostream_iterator, and its call parameters are Non-Const references. This will call the added version by overloading the resolution, the above COPY (...) will call the added version, so the parameter is a non-const reference, so next to the user's overloaded Operator <<. This solution requires the compiler to reload resolutions correctly between Const reference and Non-Const reference. -------------------------------------------------- ----------------

To everyone: I am not intended to discuss it in this question, the problem is obvious, how is the key to compromise, this is the experience of the developer who needs the library to determine it. I also don't want to consume energy on this issue, but although it is a small problem, I can see the depth and breadth of everyone thinking about the problem. I will change the article, write my key reply to the bottom, Indicates my opinion, because many friends are looking at the article, I didn't see the conclusions of my back. -------------------------------------------------- -------------------------------------------------- ---------------------------------- To Solotony: I have thought about your question, but have you want to think After: First: The programmer does not necessarily have such consciousness, once they unintentionally commit this hidden mistake (?), It has got the inconsistent compilation (or run) result, they may be at a loss. How to understand "There is no problem in the template container" in the direct output. "The most critical is that the problem is at the course of operation, even more miserable. Lights should add overload versions to this inconsistency. If it is not added, unless you have a way to prohibit the ordinary output in this case, it is obviously not possible. Second: For class to use the user's overloaded Operator <<, custom output semantic should be on the object of this class, it should be "the object knows how to output itself" instead of " How to get information about the object and output ", this" output "behavior is object ownership, not current. For objects, any stream is the same, abstract is a "pipe", which has the most basic sequence of the output. Therefore, the output is just a behavior of the object itself. Is this a CONST, then the object (class) decision - Who specifies that the object cannot change its own state when output itself? Although I can't get an example, I am definitely! At least, when this situation occurs, you can't let the user's code compile. Third: For a pointer with the "reference" semantic, what is the output it outputs it? Original, the semantics of pointers and references are very similar. In addition, in a system having an output input (SERIALIZE & UNSERIALIZE), the input and output belongs to the same system. It doesn't matter what users do. Users don't have to know which things have been output, which things are read, this is a black box, The serialization of MFC is example. One point, A is responsible for outputting a pointer, and A will also be read out, as for how to entered, all is a matter, so A will not confuse this semantic. In extreme case, a output a pointer (actually output an object) but requires B to read, then there is a "contract" between them, if A and B are developed a system two parts, then this "Contract" should be expressed as an agreement to the output input format. If b is a user, then A should provide a document (or user manual) to b. Even in the latter case, the user usually only see an object, as for this object, is still a programmer.

The only bad situation is the code reuse, which requires the programmer to have good coding habits and document habits. From another aspect, there is no habit, even if the program semantic is clear, it will cause trouble. Besides, this semantic is common, a slightly qualified code reading reader will not see the overloaded Operator <<, even if the track is also tracked. If it is binary and heavy? Obviously, returning to the black boxes mentioned above, hit. Fourth: According to Stroustrup, "Don't force programmers to do what they don't want to do, keep freedom in ambiguous thing", according to your point of view, library to some extent, the programmer must The output parameter is set to const (otherwise it is inconsistent, and the consistency is very important to avoid semantic aid). What do you have special requirements? -------------------------------------------------- -------------------------------------------------- --------------------------------------- to rainmain123: Standard library is not a black box, C standard The library meets Open Close Principle. Only binary reuse is a complete black box. STL is a scalable library, "white box" is a big bigger. In addition, what you said does make sense, I think so, but the problem here is not what side is wrong, but a problem of weighing and cons. I do this:

There are two practices here, first, maintaining the original state of Ostream_iterator, the result is:

1. Users are enforced by using ostream_iterator and custom Operator << to set its second parameters to const & (or simply

For the value copy delivery parameters, this is to force users to turn the "print themselves to output stream" CONST.

1 The problem is: (1) Although ostream_iterator has this limit, consider the following three codes:

Copy (v.begin (), v.end (), ostream_iterator (cout));

For (iter_type iter = v.begin (); it! = v.end (); iter) {cout << * ip;

For_each (v.begin (), v.end (), cout << _ 1); these three code semantics are exactly the same, and the last for_each also uses a standard library function, but their behavior is

Due to the user's overloaded Operator << and different. (2) Consider a special requirement, there is a file object, which is limited to be output once in its lifetime.

Subsequent outputs are NOP (no operation), it is clear, this is a special file, just like those "can only be read once, then automatically

The same is true. Obviously, this requirement is present. When this is encountered, the second parameter of Operator << is always

Non-constings! But ostream_iterator prevents compilation, isn't it a problem? I know that you may think

Mutable keyword, but this keyword can only solve the syntax problem, and it is not necessary to solve the semantic problem. The key here is that

If you maintain the original state of Ostream_Iiterator, it is at a very suitable for special requirements. 2. For pointers, if user-defined is Operator << (..., x * &), then ostream_iterator will output the pointer in the pointer.

Address value, and if user-defined is Operator << (..., X * const &), then output according to user-defined will. This

A behavior will be confused! Especially when Cout

Confused, unless there is a way to set COUT <

If it is inconsistent, it will cause confusion.

In general, if the status quo is maintained, there is only one extremely limited advantage, that is, when and only when the user uses Ostream_IstReerator to stream

Out, you can make sure the "output" operation is constant in the compile period. However, if the user handwrites loop output or outputs an additional function,

Ostream_Iterator is a whirling. The disadvantage is to sacrifice the support (freedom) of special circumstances, and consistency - no one look

How important is the degree of freedom and consistency.

The second approach, adds a member's Operator = (T &) function, the result is: 1. The user must pay attention to the ConSt property of the operation - this is the user's duty. Although in the former case

Ostream_iterator can play (forced) to remind the user to the extent of this, but there is no such built "reminder" capability in the language

So this compulsory reminder is extremely limited, it is still the consciousness of the user, and the consciousness is each C user.

The necessary ability - C language design concept is this: do not force users, but tell users to do the right thing. This is like Operator *

Like the overloaded, C is not mandatory, but the programmer should conscious. 2. Take into considerations of semantic consistency. 3. Provide freedom, now supporting special circumstances. -------------------------------------------------- -------------------------------------------------- ------------------------------ To cynics: You may mistakenly mean, I mean to add a weight to Ostream_Iiterator Load functions, such ostream_iterator has two versions of Operator =: ostream_iterator & operator = (_ty const &); - # 1 // The original ostream_iterator & operator = (_ty &); - # 2 // This, Regardless of how users reload Operator <<, behavior, such as:

1: Ostream & Operator << (Ostream &, X Const &);

{cout << x; // call # 1 copy (..., ostream_iterator (cout)); // Call # 1}

2: Ostream & Operator << (Ostream &, X &);

{cout << x; // Call # 2 copy (..., ostream_iterator (cout)); // Call # 2}

转载请注明原文地址:https://www.9cbs.com/read-123423.html

New Post(0)