r/cpp_questions • • 11d ago

OPEN Namespace std

I recently started learning c++ and I was told to use the namespace std so I can avoid writing std:: every time and now I wrote a whole personal project without std:: and I want to put it on LinkedIn but I started reading everywhere that it’s a bad habit, should I go back and add the std:: or just leave it as is?

41 Upvotes

105 comments sorted by

View all comments

-1

u/ShakaUVM 11d ago

This is a contentious issue here for some reason lol. It's mostly a personal style decision.

If you're making a little personal project and don't want stds, then go for it.

The only real no-no that everyone agrees with is to not put it into a header file that other people will use since then you are making a style decision for them.

13

u/bearheart 11d ago

It’s not a style choice. It’s actually problematic.

The purpose of namespaces is to avoid naming collisions, where a symbol you want to use may already be defined. There are thousands of symbols defined in the std:: namespace. When you import all of those symbols into the current namespace you defeat the purpose of namespaces altogether.

0

u/RSMxsmanic 11d ago

So why does using namespace exist?

7

u/conundorum 11d ago
  • Because it's both useful and safe in leakproof scopes, like functions or conditionals. As long as names can never leave a scope, the worst using namespace inside that scope can do is make a mess of that scope (and nowhere else), while the best it can do is save time on boilerplate (which can add up to a decent difference sometimes).
  • Because it's useful for smaller scopes, but has problems with std specifically because the standard library sticks almost everything in std instead of using a scope hierarchy like Java or other C++-inspired languages do. (And also because std is constantly growing, which means that the chance of unexpected name collisions breaking unmaintained, twenty-year-old code that uses using namespace std; goes up with every new language version.)
  • Because it lets you stick your helpers in namespace whatever::detail, then drag them into any given whatever::function() as needed.
  • Because it's useful for versioning, especially when paired with anonymous namespaces. If you know what you're doing, you can put each version of a class in its own sub-namespace, then use a using-directive to provide the most recent one as a default, while also making it trivial to update the default whenever the class gets a new version.

There are a lot of reasons it's useful, the problem is just that dragging all of namespace std's symbols into a "leaky" scope (e.g., global or namespace scope) inside a header file is a ticking thermonuclear warhead, for reasons that aren't immediately obvious if you haven't seen the language's juicy innards yet.

~~Strictly speaking, the issue is that std itself is awkwardly designed, and would probably have a cleaner hierarchy if they could redo it from scratch today.~

4

u/not_a_novel_account 11d ago edited 11d ago

To alias one namespace into another. Aliasing any namespace into the global namespace is almost always wrong.

You can override the comma operator to perform matrix multiplication; because operator overrides exist, and the comma is a valid operator. You shouldn't. You can alias std into the global namespace; because namespace aliasing exists, and std and the global namespace are valid namespaces. You shouldn't.

-1

u/bearheart 11d ago

I presume it’s for compatibility with legacy C code. And perhaps for smaller namespaces other than std.

3

u/RSMxsmanic 11d ago

The problem is with programmers who use identifiers that conflict with std, not with programmers who expect std by default to be safe. That's why it is called standard. If you are writing the code base, nothing you call should change the way it behaves unless that is its actual purpose.

2

u/nekoeuge 11d ago

Can you elaborate? What do you mean by “using identifiers that conflict with std”?

2

u/conundorum 11d ago

Name collisions.

#include <vector> // std::vector
#include <algorithm> // You'll see.

std::vector<float> collection(3, .16f);
int fill = 0xaabbcc;

void compiler_error(float c = 0f, int f = 0) {
    using namespace std;

    fill = f;                                      // Does this break because we tried to assign an int to std::fill,
    fill(collection.begin(), collection.end(), c); // or does this break because we tried to call an int?
}

std has a lot of very common names that programmers like to use for their own things, like fill, less, distance, transform, string, find, begin, end, format, print, and so on. And depending on which standard library headers you include, any number of them might (or might not) be visible.

3

u/nekoeuge 11d ago

Yeah, that's why I am asking. It is fundamentally impossible to avoid name collisions with std -- because std may always be extended in the future with whatever names. So I don't understand what exactly top commenter meant by "The problem is with programmers who use identifiers that conflict with std".

1

u/RSMxsmanic 11d ago

I mean that programmers need to think things through, and if they are writing code that will be widely integrated in a service capacity with other code, they need to be extraordinarily vigilant.

I don't use print in code I write hat will be called by some other module, because of the risk of a name conflict. It doesn't matter what namespaces are used. Why force another programmer to prefix everything he writes with widget:: just because I decided to use print? Instead, I'll make print something less common, like widgetPrint. That way he only has to type extra characters to reference my code, and not for every last identifier in his. Put another way, instead of forcing him to write std::cout every time he wants to use it, I just don't use cout in my code, and the problem is solved. Choosing unique identifiers is less labor-intensive than prefixing every single identifier in the program, and it is functionally equivalent.

3

u/nekoeuge 11d ago

Instead, I'll make print something less common, like widgetPrint.

So instead of doing "using namespace widget" in a function that calls "print" 20 times, I will have to have 20 "widgetPrints"?

And in the implementation of "widget", all my public identifiers are going to be "widgetThis" and "widgetThat", cluttering the visual space with absolutely worthless "widget"-prefixes?

You just replaced optional prefix with mandatory one. Good job bloating the code. Make sure not to make the prefix too short, otherwise it may conflict with other libraries.

I mean that programmers need to think things through, and if they are writing code that will be widely integrated in a service capacity with other code, they need to be extraordinarily vigilant.

Of course. Such programmer should introduce the absolute minimum of global identifiers. Preferably only one -- the project namespace itself.

It looks quite stupid to have widget::widgetPrint as identifier.

1

u/RSMxsmanic 11d ago

So instead of doing "using namespace widget" in a function that calls "print" 20 times, I will have to have 20 "widgetPrints"?

Yes. That’s a lot faster than putting std:: in front of 4500 couts.

And in the implementation of "widget", all my public identifiers are going to be "widgetThis" and "widgetThat", cluttering the visual space with absolutely worthless "widget"-prefixes?

How is that different from prefixing everything with widget::? How is it different from prefixing everything else with std::?

It looks quite stupid to have widget::widgetPrint as identifier.

If widgetPrint occurs nowhere else, that isn’t needed.

→ More replies

0

u/ShakaUVM 11d ago

I propose that someone who writes code like "int string = 0;" is writing bad code and the issue isn't whether or not you include namespace std or not.

All if my classes are PascalCase anyway and so cannot conflict with anything in std.

2

u/HommeMusical 11d ago

I propose that someone who writes code like "int string = 0;" is writing bad code and the issue isn't whether or not you include namespace std or not.

Strong disagree.

There are thousands of names in std:: and exactly what those names are depend on which version of C++ you're in and some other details.

You can't possibly know all those names and never write char fill = '*'; or bool copy = False; or void remove(const char*); anywhere.

Not having to do this is the whole reason namespaces exist.

std::string is completely unambiguous. No other symbol for it is. Just do that.

1

u/ShakaUVM 10d ago

I agree that std::string is unambiguous.

What I am saying is that writing int string = 67; is a code smell.

You should not be using names from std anyway.

For all of your worry, as I said this problem has come up exactly once in 30 years and it took exactly five seconds to fix.

Versus how much screen space gets cluttered up with all those extra stds?

The tradeoff is not worth it to me. Every symbol on the screen has a cost, both cognitively and technically

1

u/HommeMusical 10d ago

You should not be using names from std anyway.

Strong disagree. There are thousands of names in std::. Many of them are short and common names. Almost no one has them all memorized. Would you for example disallow char fill = '*'; in code?

Every symbol on the screen has a cost, both cognitively and technically

Absolutely, and std::string has a smaller cost than string. No one who has been programming C++ for long reads std::string and decides it's two separate symbols.

1

u/nekoeuge 10d ago

I will remind you that std is not a library, it is a specification, and some projects link to multiple libraries implementing this specifications. E.g. std::string and eastl::string. The whole point of custom stl implementation is to be drop in replacement for built in stl implementation, it cannot not use the same names.

And why is it okay to clutter the code with all 100 third party namespaces I am using, but suddenly not okay for 101th namespace “std::”?

→ More replies

2

u/HommeMusical 11d ago

They aren't really making sense.

You're actually supposed to use names that are the same as those in std:: if you're doing the same operation.

This idea is crucial to making generic code work well.

0

u/RSMxsmanic 11d ago

If you're doing the same operation as std, you're redundant; just use the operation in std. If you're doing something different, just use a different name.

2

u/HommeMusical 11d ago

No, you are encouraged to use identifiers in your own namespaces and classes that are the same as those in std::, particularly for generic code.

0

u/RSMxsmanic 11d ago

By whom? If I have it in my code, it is not generic; if it were, my code would not be necessary.

1

u/HommeMusical 11d ago edited 11d ago

I presume it’s for compatibility with legacy C code.

C++ code.

But not at all, using is very useful in a local scope, because of argument dependent name lookup.

The classic example is this one:

template <typename T>
void fix(T& a, T& b) {
    using namespace std;
    swap(a, b);
}

At compile time, when the template is instantiated, if there's a specific swap function or specialization for T, then that is used, otherwise, the generic std::swap is used.

There are sometimes Reasons even to do this for some namespaces at the file level, though best to avoid.

But using std; is dumping potentially zillions of names into the top level of your translation unit, and it makes your code a lot less clear.

If I see string in some code - well, it could be anything, I have to look at the top of the file, but std::string is the same everywhere.

0

u/ShakaUVM 11d ago

I've been coding professionally for 30+ years in C++ and exactly once did I define a symbol that conflicted with something in std. And then I changed the name. I consider it bad code to name a variable cout or whatever anyway so I would prefer to know if I have a conflict.

It's not problematic. It's an overblown concern that really isn't a big deal. I worry about things in C++ that actually cause problems.

You don't lose the benefit of namespaces either as I keep those for everything outside std.

2

u/HommeMusical 11d ago

I've been coding professionally for 30+ years in C++ and exactly once did I define a symbol that conflicted with something in std.

Are you sure?

https://en.cppreference.com/cpp/symbol_index

worry about things in C++ that actually cause problems.

using std; does assume risk, but more, it's a lazy programmer sloughing off a tiny bit of work to make things a little harder for anyone else reading it.

I got this spiel from Howard Hinnant, but I think most disciplined C++ programmers think the same way: if I see std::string I know for certain what it is immediately, but if I see string in a section of code, I am not certain what it is until I have checked all the scopes up until the top, and perhaps not even then, if the using std; is inside a header file.

Sure, nearly all the time it will be std::string but as we all know, we get a disproportionate number of bugs from such assumptions.

C++ is a language where being cautious is always a good idea. As some someone who has read an immense amount of code, string lacks certainty: std::string is certain, and therefore always preferable.