Question
Underscores in C++ Identifiers: Rules, Reserved Names, and Safe Naming
Question
In C++, it is common to use a naming convention for member variables so they are easy to distinguish from local variables or function parameters. For example, developers coming from MFC often use names like m_foo, while others use styles such as myFoo.
In C# and some .NET codebases, a common convention is to prefix member variables with a single underscore, such as _foo.
Is a name like _foo allowed by the C++ standard? More generally, what are the rules for using underscores in C++ identifiers?
Short Answer
By the end of this page, you will understand which C++ identifiers are valid, which underscore-based names are reserved by the language or standard library, and which naming styles are safe for your own code. You will also see practical examples of good and bad identifier choices for variables, functions, classes, and member variables.
Concept
In C++, identifiers are names you give to things such as variables, functions, classes, namespaces, and macros. The language allows underscores in identifiers, but there are important reservation rules.
The key idea is this:
- Some names containing underscores are perfectly fine in your code.
- Some names are reserved for the implementation, meaning the compiler, standard library, and platform headers may use them.
- If you use a reserved name yourself, your program may still compile, but the behavior is not guaranteed to be safe or portable.
The important underscore rules
In general C++ code:
_foois usually allowed for a member variable or local variable.m_foois also allowed.my_foois allowed.__foois reserved._Foois reserved.- Any identifier containing
__anywhere is reserved.
A practical beginner-friendly summary:
- A single leading underscore followed by a lowercase letter is typically safe in normal code, such as
_count. - A leading underscore followed by an uppercase letter is reserved, such as
_Count. - Two leading underscores are reserved, such as .
Mental Model
Think of identifier names like parking spaces in a shared building.
- Most spaces are for you and your team.
- Some spaces are reserved for building staff only.
- If you park in a reserved staff space, your car may not be towed immediately, but you are still breaking the rules.
In C++, underscores are like labels that can accidentally put your name into a reserved area:
_foois often like a normal space near the entrance: usually okay in the right area._Fooand__fooare like staff-only spaces: do not use them.my__foois also staff-only because the double underscore is reserved.
So the lesson is not just "can I write this name?" but also "is this name safely mine to use?"
Syntax and Examples
Basic examples
int count = 0; // OK
int my_count = 1; // OK
int _count = 2; // Usually OK in local or class scope
int m_count = 3; // OK
These are commonly acceptable names in user code.
Names you should avoid
int __count = 0; // Reserved
int _Count = 1; // Reserved
int my__count = 2; // Reserved
These names may conflict with compiler or library internals.
Member variable example
class User {
private:
std::string _name; // Commonly used, generally safe here
int m_age; // Also common and safe
public:
User(std::string name, int age)
: _name(name), m_age(age) {}
};
Step by Step Execution
Consider this example:
#include <iostream>
class Counter {
private:
int _value;
public:
Counter(int value) : _value(value) {}
void increment() {
_value++;
}
int value() const {
return _value;
}
};
int main() {
Counter c(5);
c.increment();
std::cout << c.value() << '\n';
}
What happens step by step
- The class
Counteris defined. - It has a private member variable named
_value. - The constructor
Counter(int value)receives a parameter namedvalue. - The initializer list
: _value(value)stores the parameter into the member variable.
Real World Use Cases
Underscore naming rules appear in many real C++ situations:
Class member naming
Developers often use underscores to distinguish members from parameters:
class Config {
private:
std::string file_path_;
public:
Config(std::string file_path) : file_path_(file_path) {}
};
Avoiding naming collisions in APIs
When building libraries, safe names help avoid conflicts with platform headers, compiler internals, or macros.
Cross-platform code
A name that works on one compiler may conflict on another if it uses reserved identifier patterns. Following the rules improves portability.
Large teams and style guides
Teams often choose one of these conventions:
m_name_namename_memberName
From a language-rules perspective, name_ is often the safest underscore-based style.
Generated code and tooling
Some code generators or frameworks produce identifiers automatically. Knowing reserved-name rules helps prevent invalid or risky generated names.
Real Codebase Usage
In real projects, developers usually care less about whether a name merely compiles and more about whether it is safe, readable, and consistent.
Common team conventions
Trailing underscore for members
class Session {
private:
std::string token_;
int timeout_seconds_;
};
Why teams like it:
- Avoids leading-underscore reserved-name pitfalls
- Clearly marks member variables
- Works well with constructor parameters
Session(std::string token, int timeout_seconds)
: token_(token), timeout_seconds_(timeout_seconds) {}
m_ prefix
class Session {
private:
std::string m_token;
};
This is older but still widely used, especially in legacy codebases.
Guarding against naming conflicts
In headers and public APIs, developers avoid risky names such as:
_Size__buffer
Common Mistakes
1. Using reserved names because they compile
Just because a compiler accepts a name does not mean it is safe.
int __value = 10; // Compiles on some systems, but reserved
Avoid any name with __.
2. Using underscore + uppercase letter
class Example {
int _Value; // Reserved
};
Use _value or value_ instead.
3. Using leading underscores at global scope
int _counter = 0; // Best avoided at global scope
Prefer:
int global_counter = 0;
4. Creating double underscores accidentally
int user__id = 5; // Reserved because of double underscore
Comparisons
| Naming style | Example | Usually legal in user code? | Recommended? | Notes |
|---|---|---|---|---|
| Plain name | count | Yes | Yes | Simple and safe |
| Internal underscore | user_id | Yes | Yes | Very common |
| Leading underscore + lowercase | _count | Often yes | Sometimes | Usually okay in class/local scope |
| Leading underscore + uppercase | _Count | No, reserved | No | Avoid completely |
Cheat Sheet
Safe identifier rules in C++
- Letters, digits, and underscores can appear in identifiers.
- Identifiers cannot start with a digit.
- A single underscore is not automatically illegal.
Avoid these reserved patterns
__name // reserved
_Name // reserved
my__name // reserved
Usually safe patterns
name
user_id
_value // usually okay in class/local scope
value_
m_value
Best practice
- Prefer
name_for member variables if you want to avoid reserved-name issues. - Avoid leading underscores in global names.
- Never use double underscores.
- Never use underscore followed by uppercase.
- Be consistent across the codebase.
Quick recommendation
For new C++ code:
class Example {
private:
int value_;
};
FAQ
Is _foo legal in C++?
Usually yes, especially for a local variable or class member, as long as it does not fall into a reserved pattern.
Is _Foo legal in C++?
No. An identifier beginning with an underscore followed by an uppercase letter is reserved for the implementation.
Are double underscores allowed in C++ names?
You should not use them in your own identifiers. Names with __ are reserved.
Is m_foo allowed in C++?
Yes. m_foo is a common and safe naming convention in user code.
Why do many C++ style guides prefer foo_ over _foo?
Because foo_ avoids the special reserved-name rules around leading underscores and is safer across scopes.
Can I use a leading underscore for global variables?
It is best not to. Leading underscores at global scope can conflict with implementation-reserved names.
Does the compiler always reject reserved identifiers?
No. Some reserved names may compile without errors, but they are still not safe or portable to use.
What is the safest underscore style for member variables?
A trailing underscore, such as value_, is widely considered one of the safest and clearest choices in modern C++.
Mini Project
Description
Create a small C++ program that demonstrates safe and unsafe naming conventions for identifiers. The goal is to practice recognizing which underscore-based names are good choices for your own code and which ones should be avoided because they are reserved.
Goal
Write a program with a class that uses a safe member naming convention and prints stored values clearly.
Requirements
- Create a class with at least two private member variables.
- Use a safe naming convention for the member variables.
- Add a constructor that initializes those members.
- Add getter or print functions to access the stored values.
- Include comments showing examples of reserved names that should not be used.
Keep learning
Related questions
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Base Class Constructor Rules Explained
Learn how C++ base class constructors are called from derived classes, including order, syntax, defaults, and common mistakes.
C++ Casts Explained: C-Style Cast vs static_cast vs dynamic_cast
Learn the difference between C-style casts, static_cast, and dynamic_cast in C++ with clear examples, safety rules, and real usage tips.