Expansion problems caused by generics usage in C + +

Source: Internet
Author: User
A few days ago, bloggers read an article attacking the generics of C + + causes the generated executable code to be bloated.

Bloggers engaged in C + + software development for many years, because the previous development environment are resources sufficient server, do not consider disk space problems. It is recently intended to be developed using C + + on the embedded platform of a smart home host. Flash storage space is limited, this is a must to consider the factors, we must pay attention to.

Define two lists as follows, with different element types:

List<int> l1;list<string> L2;

What should I do if I use C language? It will write a set of code corresponding to list<int>, and then write a set of list<string>. Each set has the same member function, except that the variable types are different.

The following is the C language implementation of list<int>:

//! Code-1struct List_int_item {    int value;    struct List_int_item *next;}; struct List_int {    struct list_int_item *head;    size_t size;}; void List_int_insert (struct list_int *p, int value), int  list_int_sort (struct list_int *p); bool List_int_empty ( struct List_int *p);

The following is the C language implementation of list<string>:

//! Code-2struct List_string_item {    string value;    struct List_string_item *next;}; struct List_string {    struct list_string_item *head;    size_t size;}; void List_string_insert (struct list_int *p, string value), int  list_string_sort (struct list_int *p); bool List_ String_empty (struct list_int *p);

The difference between the two is the type. So a lot of time, in C language we use the macro to replace its type, as follows:

//! Code-3#define list_declare (TYPE) \    struct list_# #TYPE # #_item {\        type## value; \        struct list_# #TYPE # #_item *next; \    }; \    \    struct list_# #TYPE {\        struct list_# #TYPE # #_item *head; \        size_t size; \    }; \    \ \    void list_# #TYPE # #_insert (struct list_# #TYPE *p, # #TYPE # # value); \    int  list_# #TYPE # #_sort (struct list_# #TYPE *p), \    bool list_# #TYPE # #_empty (struct list_# #TYPE *p); \< c19/> ...

The list<double> is then defined in the header file:

//! Code-4list_declare (Double)

Therefore, generics generate redundant code is unavoidable, at least in C to do such a generic is unavoidable.

Since it is unavoidable, let's see how to avoid the above problems as much as possible. In "Effective C + +" There is a section specifically mentioned: Do not use unnecessary parameters in the template. Because each of the different parameter compilers generates a set of corresponding code for it.

If there is only one data type in the code, even if multiple variables are defined with that type, will the compiler generate only a set of related code? (This should be the case).

Write an example to compare: (omit unnecessary code)

Test1.cpp, inside only Map<int, STRING>, but defined M1, M2, M3.

//! Code-5    Map<int, string> M1;    Map<int, string> m2;    Map<int, string> m3;    M1.insert (Std::make_pair (1, "Hello"));    M2.insert (Std::make_pair (1, "HI"));    M3.insert (Std::make_pair (1, "Lichunjun"));

Test2.cpp, compared with the test1.cpp, there are three types:

//! Code-6    Map<int, string> M1;    Map<int, double> m2;    Map<int, int> m3;    M1.insert (Std::make_pair (1, "Hello"));    M2.insert (Std::make_pair (1, 1.2));    M3.insert (Std::make_pair (1, 44));

As a result, the compiled executable file size is compared:

[Hevake_lcj@hevake tmp]$ ll Test1 test2-rwxrwxr-x. 1 18784 Mar 22:01 test1-rwxrwxr-x. 1 35184 Mar 22:03 test2

Test2 is one-fold bigger than test1, and the reason is not to say much.


There is one more question: is the pointer considered a type?

The above list<int> and list<string> cannot share the same set of code, depending on the reason that the two types of int and string are different in the way the space size and assignment are. Therefore, you must generate two sets of code to implement.

and pointers, no matter what the pointers are, are the same. We can use void* to represent all the pointer types.

So we changed the code above and tested it again:

//! Code-7    Map<int, string*> M1;    Map<int, string*> m2;    Map<int, string*> m3;    M1.insert (Std::make_pair (1, new string ("Hello"));    M2.insert (Std::make_pair (1, new string ("HI"));    M3.insert (Std::make_pair (1, new string ("Lichunjun"));

And

//! Code-8    Map<int, string*> M1;    Map<int, double*> m2;    Map<int, int*> m3;    M1.insert (Std::make_pair (1, new string ("Hello"));    M2.insert (Std::make_pair (1, new double (1.2)));    M3.insert (Std::make_pair (1, new Int (44)));

The result is this:

-rwxrwxr-x. 1 18736 Mar 23:05 test1-rwxrwxr-x. 1 35136 Mar 23:05 test2

The expected results test1 and test2, but there is no optimization from the results, the result is a bit disappointing ~


Think: does C + + have any parameters to optimize this?

If not, in order to save space, we can only define all the pointers uniformly as void* types, and then cast them when used.

//! Code-9    Map<int, void*> M1;    Map<int, void*> m2;    Map<int, void*> m3;    M1.insert (Std::make_pair (1, new string ("Hello"));    M2.insert (Std::make_pair (1, new double (1.2)));    M3.insert (Std::make_pair (1, new Int ()));    cout << *static_cast<string*> (m1[1]) << Endl;    cout << *static_cast<double*> (m2[1]) << Endl;    cout << *static_cast<int*> (m3[1]) << Endl;

As the above code is based on the code-8, all designations are defined as void*, which are coerced into the corresponding pointer type when used with static_cast.

The resulting code size is 16 more bytes compared to code-7.

However, it is not advisable to use the void* pointer after the compiler does not check the type, it is easy to confuse the type.

  • Related Article

    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.