C ++ Engineering Practice (1): use anonymous namespace with caution

Source: Internet
Author: User

Anonymous namespace (anonymous namespace or unnamed namespace) is a very useful function of C ++. Its main purpose is to make members (variables or functions) in the namespace) it has a unique global name to avoid name collision (name collisions ). When writing a. cpp file, if you need to write some small helper functions, we usually put them in the anonymous namespace. In muduo 0.1.7, muduo/base/Date. cc and muduo/base/Thread. cc use the anonymous namespace.

I recently encountered this problem with my new thoughts and found that anonymous namespace is not a lot of advantages.

Two usage methods of static keywords in C Language
The static keyword of C language has two purposes:

1. It is used to modify the variable inside the function, that is, the static variable in the function. The lifetime of this variable is longer than that of this function, so that the function has a certain "State ". Functions that use static variables are generally not reentrant, nor thread-safe.

2. When a variable or function is modified at the file level (outside the function body), it indicates that the variable or function is visible only in this file. Other files cannot see or access the variable or function. The professional statement is "having internal linkage" (in short, it is not exposed to other translation units ).

The usage of C language is clear and generally not confusing.

Four usage of static keywords in C ++
Because C ++ introduces class, while maintaining compatibility with C language, the static keyword has two new usage methods:

3. It is used to modify the data member of the class, that is, the so-called "static member ". The lifetime of the data member is greater than the object (entity instance) of the class ). Static data members have one copy for each class, and common data members have one copy for each instance. Therefore, they are also called class variable and instance variable.

4. The member function used to modify the class, that is, the so-called "static member function ". This type of member function can only access class variable and other static program functions, but cannot access instance variable or instance method.

Of course, these usage types can be combined with each other. For example, the member functions of C ++ (both static and instance) can have their local static variables (usage 1 above ). For the class template and function template, the real number of static objects is related to the template instantiation (the template is now available). I believe that those who have learned the C ++ template will not be unfamiliar.

It can be seen that static is overloaded multiple times in C ++. The introduction of anonymous namespace is to reduce the burden on static. It replaces the 2nd usage of static. That is to say, the file-level static keyword is not required in C ++. We can use anonymous namespace to achieve the same effect. (In fact, the linkage may be slightly different. We will not discuss it here .)

Disadvantages of anonymous namespace
In engineering practice, anonymous namespace has two major disadvantages:

It is difficult to set breakpoints for functions. If you use text mode debugger like gdb.
When g ++ is used in some versions, the binary files compiled by the same file change each time, which causes some build tools to fail.
Consider the following short code (anon. cc ):

1: namespace 2: {3: void foo () 4: {5:} 6:} 7: 8: int main () 9: {10: foo (); 11 :}
For Question 1:
The auto-completion function of gdb helps us set breakpoints, which is not a big problem. The premise is that you know that "(anonymous namespace): foo ()" is exactly the function you want.

$ Gdb./a. out
GNU gdb (GDB) 7.0.1-debian

(Gdb) B
(Anonymous namespace) _ data_start _ end
(Anonymous namespace): foo () _ do_global_ctors_aux _ fini
_ DYNAMIC _ do_global_dtors_aux _ init
_ GLOBAL_OFFSET_TABLE _ dso_handle _ start
_ IO_stdin_used _ gxx_personality_v0 anon. cc
_ CTOR_END _ gxx_personality_v0 @ plt call_gmon_start
_ CTOR_LIST _ init_array_end completed.6341
_ DTOR_END _ init_array_start data_start
_ DTOR_LIST _ libc_csu_fini dtor_idx.6343
_ FRAME_END _ libc_csu_init foo
_ JCR_END _ libc_start_main frame_dummy
_ JCR_LIST _ libc_start_main @ plt int
_ Bss_start _ edata main

(Gdb) B (
Anonymous namespace): foo ()

(Gdb) B (anonymous namespace): foo ()
Breakpoint 1 at 0x400588: file anon. cc, line 4.

The trouble is that if two files are anon. cc and anonlib. cc defines the foo () function in the anonymous space (this will not conflict with each other), so gdb cannot distinguish the two functions. You can only set a breakpoint for one of them. Or you can use the file name: row number to set breakpoints separately. (Technically, the function in the anonymous namespace is local text. linker will not report an error if the name is duplicated during the link .)

The fundamental solution is to use a common named namespace. If you are afraid of duplicate names, you can use the source file name (add the path if necessary) as part of the namespace name.

For Question 2:
Compile it twice to generate a. out and B. out respectively:

$ G ++-g-o a. out anon. cc

$ G ++-g-o B. out anon. cc

$ Md5sum a. out B. out
0f7a9cc15af7ab1e57af17ba16afcd70 a. out
8f22fc2bbfc27beb922aefa97d174e3b B. out

$ G ++ -- version
G ++ (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu4)

$ Diff-u <(nm a. out) <(nm B. out)
---/Dev/fd/63 22:27:58. 960754999 + 0800
++/Dev/fd/62 22:27:58. 960754999 + 0800
@-+ @@
0000000000600940 d _ GLOBAL_OFFSET_TABLE _
0000000000400634 r_ IO_stdin_used
W_jv_registerclasses
-0000000000400538 t _ zn36_global1_n _ anon. cc_1_1__e2ceeb513fooev
+ 0000000000400538 t _ zn36_global1_n _ anon. cc_00000000_CB51498D3fooEv
0000000000600748 d _ CTOR_END __
0000000000600740 d _ CTOR_LIST __
0000000000600758 d _ DTOR_END __


As shown in the preceding figure, g ++ 4.2.4 randomly generates a unique name (E2CEEB51 and CB51498D In the mangled name of the foo () function for the anonymous namespace ), to ensure that the name does not conflict. That is to say, the two compiled binary files of the same source file are different, which sometimes causes problems. For example, if a binary executable file with core dump is obtained, it cannot be determined which revision code is compiled. After all, the compilation results cannot be reproduced and are random.

This can be solved using the-frandom-seed parameter of gcc. For details, see the document.

This phenomenon exists in gcc 4.2.4 (the previous version is estimated to be similar) and does not exist in gcc 4.4.5.

Alternative
If the previous "disadvantage" brings you troubles, the solution is very simple, that is, using a common namespace. Of course, a good name is required. For example, boost: detail is often used in boost to put functions or classes that "should not be exposed to customers, but must be put in header files.

All in all, anonymous n

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.