I've used this approach in the past:
using Atom = const char*;
Atom make_atom(string const& value)
{
static set<string> interned;
return interned.insert(value).first->c_str();
}
Obviously, if you want/need to clear the set, you'd make it available in some wider scope.
For even more efficiency move/emplace the strings into the set.
Update I've added this approach for completeness. See it Live on Coliru
#include <string>
#include <set>
using namespace std;
using Atom = const char*;
template <typename... Args>
typename enable_if<
is_constructible<string, Args...>::value, Atom
>::type emplace_atom(Args&&... args)
{
static set<string> interned;
return interned.emplace(forward<Args>(args)...).first->c_str();
}
#include <iostream>
int main() {
cout << emplace_atom("Hello World\n");
cout << emplace_atom(80, '=');
}