STL notes (5) clause 49: Learn to crack compiler diagnostic information about STL

Source: Internet
Author: User

STL notes (5) clause 49: Learn to hack compiler diagnostic information about STL clause 49: Learn to crack compiler diagnostic information about STL

It is perfectly legal to define a vector with a specific size,

Vector<int> V (10); Build a vector of size 10

And string is like a vector in many ways, so you might want to do this:

string s (10); Common sense to create a string of size 10

This cannot be compiled. The string does not have a constructor with an int argument. One of my STL platforms tells me that point like this:

Example.cpp: Error C2664: ' __thiscall std::basic_string<char, Structstd::char_traits<char>,class std:: allocator<char> >::std::basic_string<char,struct Std::char_traits<char>,class Std::allocator <char> > (const classstd::allocator<char> &) ': cannot convert parameter 1 from ' const int ' to ' Constclas S std::allocator<char> & ' Reason:cannot convert from ' const int ' to ' Constclass Std::allocator<char>no Co Nstructor could take the source type, or constructor overload resolution was ambiguous

Isn't it wonderful? The first part of the message looks like a cat walking through the keyboard, the second part mysteriously mentions an allocator that has never been involved in the source code, and the third part says that the constructor call is wrong. Of course, the third part is accurate, but first let's focus on the results of the cat walk, because when using string, this is typical of the diagnostic information you often encounter.

String is not a class, it is a typedef. In fact, it is the typedef of this:

Basic_string<char, Char_traits<char>, allocator<char> >

This is because the C + + concept of a string has been generalized to a sequence of any character type that represents an arbitrary character attribute ("traits") and is stored in memory classified as an arbitrary allocator. All strings-like objects in C + + are actually instances of the basic_string template, which is why the type basic_string is involved when most compilers issue diagnostic information about "program error using string". (Some compilers are kind and use string names in diagnostic information, but most do not.) In general, such diagnostic information clearly states that basic_string (and service helper templates char_traits and allocator) are in the Std namespace, so it is often seen that the error call string produces a reference to this type of diagnostic information:

Std::basic_string<char, Std::char_traits<char>, std::allocator<char> >

This is very close to the diagnostic information used in the compiler above, but different compilers use different variants of this theme. Another STL platform I'm using represents a string in this way,

Basic_string<char, String_char_traits<char>, __default_alloc_template<false,0> >

The names of String_char_traits and __default_alloc_template are non-standard, but that is life. Some STL implementations deviate from the standard. If you don't like the divergence in your current STL implementation, consider replacing it with another one. Clause 50 gives you an example of where you can find an alternative implementation.

Regardless of how the compiler diagnostic information represents a string type, the technique of reducing the diagnostic information to something meaningful is the same: replace the cumbersome basic_string with the literal "string". If you're using a command-line compiler, it's often easy to do this with a program like SED or a scripting language like Perl, Python, or Ruby. (You can find an example of such a script in Zolman's article, "Visual C + + STL error message Decoder" [26]--]. In the case of the above diagnostic information, we replace it with a string global

Std::basic_string<char, struct Std::char_traits<char>,class std::allocator<char> >

Can get this:

Example.cpp: Error C2664: ' __thiscall string::string (const classstd::allocator<char> &) ': Cannot convert Parameter 1 from ' const int ' to Constclass std::allocator<char> & '

It is clear (or at least more clearly) that the problem is in the parameter type passed to the string constructor, even though the allocator<char> is still mysteriously mentioned, but it is easier to see that there is no string constructor form with only size.

Incidentally, the reason for the mysterious reference to the allocator is that each standard container has a constructor with only the allocator. In the case of string, it is one of three constructors that can be called with one argument, but for some reason the compiler indicates that the one with the allocator is what you are trying to invoke. The compiler is wrong, and the diagnostic information is misleading. Oh yo.

For constructors with only allocators, do not use it. The constructor is designed to make it easy to construct containers of the same type but with unequal prices for allocators. Usually, that is not good, very bad. To know why, turn to clause 11.

Now let's deal with more challenging diagnostic information. Suppose you are implementing an e-mail program that allows users to look up people through nicknames rather than email addresses. For example, such a program would probably use "the Big Cheese" as a synonym for the U.S. president (which happens to be [email protected]) e-mail address. Such programs can use a mapping from nickname to email address, and may provide a member function showemailaddress, which displays the email address associated with the given nickname:

Class Niftyemailprogram{
Private
typedef map<string, string> Nicknamemap;
Nicknamemap nicknames; From nickname to email
Mapping of Addresses
Public

void Showemailaddress (const string& nickname) const;
};

Inside showemailaddress, you need to find the mapping portal associated with a particular nickname, so you might write:

void Niftyemailprogram::showemailaddress (const string& Nickname) const
{

Nicknamemap::iterator i = Nicknames.find (nickname);
if (i! = nicknames. End ())

}

The compiler does not like this, and there are good reasons, but the reasons are not obvious. To help you point it out, this is an STL platform that has been helped to send out:

Example.cpp: Error C2440: ' Initializing ': cannot convert from ' Classstd::_tree<class Std::basic_string<char, struct std::char_traits<char>,classstd::allocator<char> >,struct std::p air<class std::basic_ String<char, Structstd::char_traits<char>,class std::allocator<char> > Const. CLASSSTD::BASIC_ String<char, struct std::char_traits<char>,class std::allocator<char> >>,struct std::map< Class Std::basic_string<char, Structstd::char_traits<char>,class std::allocator<char> >.class std :: Basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less <classstd::basic_string<char,structstd::char_traits<char&gt, Classstd::allocator<char> >, Class Std::allocator<class Std::basic_string<char, Struct,std::char_traits<char>,class std::allocator <char> > > >::_kfn, Structstd::less<class std::basic_string<char, StrucT std::char_traits<char>,classstd::allocator<char> > >,class std::allocator<class std::basic_ String<char, Struct,std::char_traits<char>,class std::allocator<char> > > >::const_iterator ' To ' classstd::_tree<class Std::basic_string<char, struct std::char_traits<char>,classstd::allocator <char> >,struct std::p air<class Std::basic_string<char, Structstd::char_traits<char>,class std ::allocator<char> > Const. Classstd::basic_string<char, struct Std::char_traits<char>,class std:: Allocator<char> >>,struct std::map<class Std::basic_string<char, Structstd::char_traits<char >,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char> Class Std::allocator<char> >,struct Std::less<classstd::basic_string<char,structstd::char_traits <char> .classstd::allocator<char> > >,class std::allocator<class std::baSic_string<char,structstd::char_traits<char>,class std::allocator<char> > > >::_Kfn, Structstd::less<class Std::basic_string<char, struct std::char_traits<char>,classstd::allocator< char> > >,class std::allocator<class std::basic_string<char, Structstd::char_traits<char> Class std::allocator<char> > > >::iterator ' No constructor could take the source type, or constructor Overlo Ad resolution was ambiguous

There are 2,095 characters long, this message looks pretty scary, but I've seen worse. For this example one of my favorite STL platforms produces a 4,812-byte diagnostic message. As you can guess, the nature of the error message is the reason I love it.

Let's reduce this group of mess to something that is easy to handle. Let's start by replacing the basic_string with a string. can produce this:


Std::_tree<class string, struct std::p air<class string Const,class string >,structstd::map<class string, Class string, struct Std::less<class string >,classstd::allocator<class string > >::_kfn, struct std:: Less<class string >,classstd::allocator<class string > >::const_iterator ' to ' class Std::_tree<class String,struct std::p air<class string Const. class string >,struct std::map<class string,class string, struct STD :: Less<class string >,class std::allocator<class string>>::_kfn,struct std::less<class string; Class Std::allocator<class String>>::iterator ' No constructor could take the source type, or constructor overload Resolution was ambiguous

Much better. Now that we've lost weight to 745 characters, we can really start to see the news. One of the things that is likely to draw our attention is the template std::_tree. The standard did not say a template called _tree, but the leading underscore in the name followed by an uppercase letter evokes our memory--the name is reserved for implementation. This is an internal template used to implement some parts of the STL.

Virtually all STL implementations use some intrinsic template to implement standard associative containers (set, Multiset, map, and Multimap). Just as the source code using string often causes diagnostic information to refer to basic_string, the use of standard associative container source code often causes diagnostic information to refer to some intrinsic tree templates. Here, it is called _tree, but other implementations I know use __tree or __rb_tree, which reflect the use of red-Haishi-the most common type of balance tree used in STL implementations. The knowledge of the red and black tree can be found in the relevant books of the data structure or algorithm. )

Put the _tree aside first, the message above mentions a type we have to recognize: Std::map<class string, class string, struct Std::less<class string>, class Std :: Allocator<class string > >. This is exactly the type of map we are using, in addition to showing the comparison and allocator types (we did not specify them when we defined the map). If we replace it with that type of typedef--nicknamemap--, the error message will be easier to understand. And that's what this is about:

Example.cpp: Error C2440: ' Initializing ': cannot convert from ' classstd::_tree<class string, struct std::p air< Class string Const, class string >,structnicknamemap::_kfn, struct Std::less<class string >,class std:: allocator<classstring > >::const_iterator ' to ' class Std::_tree<class string, struct std::p air< Classstring const, class string >,struct nicknamemap::_kfn, struct std::less<classstring >,class std:: Allocator<class string > >::iterator ' No constructor could take the source type, or constructor overload Resolutio N was ambiguous

This message is shorter, but much clearer. We need to do something about _tree. Because _tree is an implementation-specific (implementation-specific) template, the only way to know the meaning of its template parameters is to read the source code, and if not, there is no reason to go through the implementation of a particular source code. Let's try to just replace all of the _tree with something to see what we get. Here is the result:

Example.cpp: Error C2440: ' Initializing ': cannot convert from ' classstd::_tree<something>::const_iterator to ' Classstd::_tree<something>::iterator ' No constructor could take the source type, or constructor overload Resolution was ambiguous

This is something we can deal with. The compiler complains that we are trying to convert some kind of const_iterator into iterator, a significant damage to the correctness of the constants. Let's look at that nasty piece of code again, and I've highlighted the line that caused the compiler to rage:

Class Niftyemailprogram{
Private
typedef map<string, string> Nicknamemap;
Nicknamemap nicknames;

Public

void Showemailaddress (const string& nickname) const;
};

void Niftyemailprogram::showemailaddress (const string& Nickname) const
{

Nicknamemap::iterator i = Nicknames.find (nickname);
if (i! = Nicknames.end ())

}

The only meaningful explanation is that we are trying to initialize I (is iterator) with a const_iterator returned from Map::find. That seems odd, because we are nicknames up with find, and nicknames is in the very object, find should therefore return the very amount of iterator.

Look again. Yes, nicknames is declared as a very mass map, but showemailaddress is a const member function, and inside a const member function, all non-static data members of the class become constants! Inside Showemailaddress, nicknames is a constant map. Suddenly the error message is meaningful. We are trying to produce a iterator in the map we promised not to change. To solve this problem, we must change I to const_iterator or we must make showemailaddress a non-const member function. These two solutions may be less challenging than finding the wrong message.

In this article, I demonstrate the complexity of reducing error messages with the original text, but once you practice a little, you will be able to replace them in your mind for most of the time. I am not a musician (I have trouble with the radio), but others tell me that good musicians can read a few bars at a glance; they don't need to see independent notes. Experienced STL programmers develop a similar skill. They can std::basic_string<char, struct std::char_traits<char> in the interior without hesitation; class std::allocator<char> > translated to String. You also need to develop this skill, but before you can, remember that you can always reduce compiler diagnostic information to understandable by replacing lengthy template-based type names with shorter memory. On many occasions, all you have to do is replace the typedef with the TypeDef name you have already used. That's where we replace Std::map<class string, class string, struct Std::less<class string with Nicknamemap, class::allocator< Class String > >.

Here are some other tips that should help you understand compiler messages about STL:

  • For vectors and strings, iterators are sometimes pointers, so if you make an error with an iterator, the compiler diagnostic information might refer to the pointer type involved. For example, if your source code involves vector<double>::iterator, the compiler message will sometimes refer to the double* pointer. (A notable exception is when you use STL implementations from STLport, and you run in debug mode.) In that case, the iterators of vectors and strings are simply not pointers. For more information on STLport and its debug mode, turn to clause 50. )
  • The mention of Back_insert_iterator, Front_insert_iterator, or insert_iterator often means that you have mistakenly called Back_inserter, Front_ Inserter or Inserter, each of which corresponds, (Back_inserter returns an object of type Back_insert_iterator, Front_inserter returns an object of type Front_insert_iterator, Instead, Inserter returns an object of type Insert_iterator. For information on the use of these inserter, refer to clause 30. If you do not call these functions, you (directly or indirectly) call some of the functions done.
  • Similarly, if you get a message that mentions binder1st or binder2nd, you may have used the bind1st or bind2nd incorrectly. (bind1st returns an object of type binder1st, and bind2nd returns an object of type binder2nd.) )
  • The
  • output iterator (for example, Ostream_iterator, ostreambuf_iterators (see clause 29), and the Back_inserter, Front_ Inserter and Inserter return iterators) do output or insert work inside the assignment operator, so if you mistakenly use one of these iterator types, you're likely to get a message complaining about something in an assignment operation character you've never heard of. To understand what I mean, try compiling this code:vector<string*> v;                     //  tried to print a
    copy (V.begin (),  v.end (),                 // string * Pointer to the container,
        ostream_iterator<string> (cout,  "\ n"));     //   is treated as a string object
  • You get an internal error message from the STL algorithm (that is, the source code throws an error in <algorithm>), maybe you tried to give the algorithm a wrong type. For example, you might have passed an iterator of the wrong kind. To see how this usage error is reported, Enlighten (and be happy!) by feeding the code to your compiler.        ) Himself: List<int>::iterator I1, I2; The bidirectional iterator
    Sort (i1, i2); Pass to a need
    Algorithms for random access iterators
  • You use common STL components such as the vector, string, or For_each algorithm, and the compiler says you don't know what you're talking about, and you probably don't have a header file that you need to include. As explained in clause 48, this problem will befall code that has been successfully compiled for a long time and has just been ported to a new platform.

STL notes (5) clause 49: Learn to crack compiler diagnostic information about STL

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.