2

I asked this question: Array Equivalent of Bare-String

To which the answer was C++ doesn't provide this functionality for const int*s. Which is disappointing. So my question then is: In practice how do I get around this limitation?

I want to write a struct like this:

struct foo{
    const char* letters = "abc";
    const int* numbers = ???
};

I cannot:

  1. &{1, 2, 3} cause I can't take the address of an r-value
  2. array<int, 3>{{1, 2, 3}}.data() cause the memory is cleaned up immediately after initialization
  3. const int* bar(){ return new int[3]{1, 2, 3}; } cause nothing will delete this pointer

I know that I can use an auto pointer to get around this. I am not suggesting that struct foo is good code, I am trying to illustrate that the compiler makes a provision to store the const array "abc" in memory and clean it up on program exit, I want there to be a way to do that for ints as well.

Is there a way to accomplish this?

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • Considering you didn't put a `c` tag to this question, I suggest making it a class and choose option 3. – user3528438 Apr 24 '15 at 13:20
  • What is wrong with using `const int numbers[] = {1, 2, 3};`? – NathanOliver Apr 24 '15 at 13:22
  • @user3528438 As stated in the question: "I am not suggesting that struct foo is good code... I want there to be a way to do that for ints as well." The question is not about how to write `foo`. – Jonathan Mee Apr 24 '15 at 13:23
  • @NathanOliver There is nothing wrong with that for writing a better `struct foo` but that's not what I want to know about. I want to know how to put an `int[]` into the const memory where C++ stores `"abc"` and have it clean it up at the end of program execution. – Jonathan Mee Apr 24 '15 at 13:25

3 Answers3

6

How about a static which you point to - I think this what the compiler pretty much does internally for "strings literals" anyway?

static const int Numbers[] = {1, 2, 3};

struct foo{
    const char* letters = "abc";
    const int* numbers = Numbers;
};
Mike Vine
  • 9,468
  • 25
  • 44
  • I like it, I don't know why I didn't think of that. – Jonathan Mee Apr 24 '15 at 13:26
  • @Reader I have a solution based on [Ben Voigt](http://stackoverflow.com/users/103167/ben-voigt)'s answer: http://stackoverflow.com/a/29850546/2642059 But that should not be considered more than a parlor trick because of the 2 drawbacks mentioned in the answer. The only drawback to this answer is the namespace pollution which can be combated by use of the anonymous namespace. Using that tactic this is the correct answer. – Jonathan Mee Apr 27 '15 at 10:59
2

String literals are all you get. However, they are also enough to cover most integral data. In your case you can use

L"\1\2\3"

to get a compiler-managed array of wide characters. C++11 and later also support u8, u16, and u32 strings.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Is `wchar_t` guaranteed to be the same size as `int` in C++? If not, is it a problem? – eerorika Apr 24 '15 at 13:30
  • @user2079303: No, it is not guaranteed. On Win32, it never is. Still, you can store non-trivial data in a string literal. – Ben Voigt Apr 24 '15 at 13:33
  • @BenVoigt Hmmm... Is that `L` an operator of sorts? Seems like I could correctly decide the type and string char size with templates at compile time? – Jonathan Mee Apr 24 '15 at 13:35
  • @JonathanMee: You can definitely detect which extended character type is the same size as `int` at compile-time. The `L` is part of the literal though, not sure about substituting it other than with a macro. – Ben Voigt Apr 24 '15 at 13:38
  • @BenVoigt I've added [an answer](http://stackoverflow.com/a/29850546/2642059) which accomplishes this in a macro. I wish that the user could just do `QUOTATION(1, 2, 3)` but that's probably just too much to handle in a macro. – Jonathan Mee Apr 24 '15 at 14:49
1

We can accomplish this using Ben Voigt's answer:

const int* numbers = sizeof(int) == sizeof(char32_t) ? reinterpret_cast<const int*>(U"\1\2\3") : reinterpret_cast<const int*>(u"\1\2\3");

The ternary is compiled out as is evidenced by the fact that you can declare numbers as constexpr.

There are a couple drawbacks to this implementation:

  1. This is actually a wchar_t string literal you will get a terminating 0 element in addition to any characters you specify
  2. This assumes that an int will be either 32-bits or 16-bits, if that's not the case this will try to cast from a char16_t to a whatever sized int and you will have major problems

In any case we can simplify this into a macro:

#define QUOTATION(x) sizeof(int) == sizeof(char32_t) ? reinterpret_cast<const int*>(U ## x) : reinterpret_cast<const int*>(u ## x)

Which can be used like:

const int* numbers = QUOTATION("\1\2\3"); 
Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288