Ensure that char pointers always point to the same string literal

依然范特西╮ 提交于 2020-01-02 23:13:13

问题


Given the code

// somewhere in the program
const char* p1 = "Hello World";

// somewhere else in the program
const char* p2 = "Hello World";

is there a way to ensure that p1 == p2 is always satisfied within the entire program / library? By that I mean that p1 and p2 always refer to the same string literal.

The Reason behind it

What I'm trying to achieve is to use const char* as a key for std::map<const char*, something>. I have a macro

#define nameof(id) #id

that mimics the behavior of the nameof keyword in C# (I know this is already flawed) and I want to use it to access a registry like structure, for example

void foo()
{
    auto x = getMapping(nameof(foo));
}

// different place in code

void registerFoo(something x)
{
    setMapping("foo", x);
}

回答1:


As Barry shows in their answer the behavior you want is not guaranteed. You're going to have to pay the cost of string comparisons, but you can at least avoid any memory allocations or writing a comparator by using a std::string_view. A std::string_view is a lightweight view of a string that holds a pointer to the string data and the size of the string and it has a built in operator < that will do a lexicographical comparison. That would change your map to

std::map<std::string_view, something>



回答2:


There is no such requirement. [lex.string]/15:

Whether all string literals are distinct (that is, are stored in nonoverlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified.

Best you can do is assert() or just avoid repeating yourself and stick the thing in a function:

char const* my_literal() { return "Hello World"; }

char const* p1 = my_literal();
char const* p2 = my_literal();



回答3:


Identical literal strings are not guaranty to be identical, but as you use MACRO to create the string, you can change it to return identical string.

gcc/clang have an extension to allow to build UDL from literal string:

template<typename Char, Char... Cs>
struct CsHelper
{
    static constexpr const Char s[] = {Cs..., 0}; // The unique address
};

// That template uses the extension
template<typename Char, Char... Cs>
constexpr auto operator"" _cs() -> const Char (&)[1 + sizeof...(Cs)] {
    return CsHelper<Char, Cs...>::s;
}

and then

#define nameof(id) #id ## _cs

See my answer from String-interning at compiletime for profiling to have MAKE_STRING macro if you cannot used the extension (Really more verbose, and hard coded limit for accepted string length).




回答4:


There is no requirement that two string literals with the same text are the same object. So the two mentions of ”Hello world” may or may not refer to a single string in memory. That means that

const char* p1 = "Hello World";
const char* p2 = "Hello World";

Does not necessarily make p1 equal to p2. To do that, you have to set one of them equal to the other:

const char* p2 = p1;

But either one of those pointers can be modified, and the other pointer won’t track that change. To make sure that such changes can’t be done, make the pointers const:

const char* const p1 = "Hello World";
const char* const p2 = p1;

Or, if p1 needs to be modifiable, make p2 a reference:

const char* p1 = "Hello World";
const char*& p2 = p1;

Now p2 will point at whatever p1 points at.



来源:https://stackoverflow.com/questions/58866964/ensure-that-char-pointers-always-point-to-the-same-string-literal

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!