Bolian
Bolian

Reputation: 61

c++ create an array with string::size

Im trying to create an array with the string::size member but its complaining at the declaration of "char message[msgSize]" that the expression did not evalute to a constant.

However it alows me to declare "msgSize".

How can this be? Why am i allowed to make a constant but i'm not allowed to use it to something that needs a const.

If the answer is that: "the size of the string could change" then the same argument can be made for using sizeof(), but that works.

const unsigned int msgSize = 
        saveAs.size() +
        sizeof("NOTE|  sent get request to: ") + 10;

    char message[msgSize];
    memset(message, 0, msgSize);
    sprintf_s(message, msgSize,"NOTE| sent get request to: %s", saveAs.c_str());
    _cRec->output(message);

Upvotes: 2

Views: 1576

Answers (5)

Jorge Omar Medra
Jorge Omar Medra

Reputation: 988

You need a compile-time constant with char message[msgSize]; because this is a local variable which uses static memory that is allocated in the data segment, so the compiler needs to calculate the number of bytes required by the code, including the local variables and arrays.

You can use dynamic memory to solve your problem. The dynamic memory is allocated in the heap. In C, you should use malloc(). In C++, you should use new[] (or better, std::vector, or even std::string). Then you can specify the memory size using a runtime value in a variable.

So, your code would look more like the follow:

char* message = new char[msgSize]; //Allocated memory
//Do everything that you need...
delete[] message; //Release memory

Or:

#include <vector>

std::vector<char> message(msgSize); //Allocated memory
//Do everything that you need...

Upvotes: 0

smac89
smac89

Reputation: 43078

Why am i allowed to make a constant but i'm not allowed to use it to something that needs a const.

This is because the "constant" expression you have is made up of non constant parts i.e. the size method of the string class. It is not truly constant in terms of having a known value at compile time.

Consider using constexpr variable/function in the future

If the answer is that: "the size of the string could change" then the same argument can be made for using sizeof(), but that works.

No that same argument cannot be used for sizeof because sizeof does not need it's arguement to be a constant.


If you know for a fact that saveAs contains a string with a known size, then perhaps it would be best if you declare that size as a constant and then refer to it in your calculation:

constexpr unsigned int msgSize = 
        SAVEAS_SIZE +
        sizeof("NOTE|  sent get request to: ") + 10;

Then this will allow you to do:

char message[msgSize];

Upvotes: 0

luk32
luk32

Reputation: 16070

Well const just means that you promise that the value won't change. And you can even override that with a const_cast.

What compiler needs there is a value that can be evaluated at the compile time. This is a stronger requirement. Such values are marked with constexpr keyword.

Unfortunately you are out of luck with std::string... size() is not a constexpr.

I played with the following example:

#include <iostream>
#include <string>
using namespace std;

const string msg("Some msg");
constexpr int msg_len = msg.size();

int main() {

    char msg[msg_len];

    cout << sizeof(msg);
    return 0;
}

The thing is that size() is not a constexpr, and you cannot make string a constexpr because it has a non-trivial destructor.

Why it is designed this way is beyond me. Seems like a counter intuitive and serious limitation. However, there are pretty clever implementation of string, for example with small storage optimization. It might be hard to make them constexpr with out serious changes in the implementation.

Upvotes: 1

BiagioF
BiagioF

Reputation: 9705

In C++ you cannot declare VLAs.

When you declare an array, for example:

char message[x];

The expression x must to be valuable at compile time, that is its value has to be well-known when the source is compiled.

In you example:

char message[msgSize];

The expression (variable) msgSize is not known at compile time, but only at run time. That because the compiler has to know how many bytes reserve in the stack.

Note: the variable msgSize is a constant value. A constant value is not an expression evaluate at compile time. It simply means that its value cannot change once has been assigned.

In C++11 has been introduced the keywork constexpr in order to define an expression which should be evaluate at compile time.

However in your case there is not way to get the size of a dynamic string at compile time. So what you have to do is use dynamic array (dynamic memory).

char* message = new char[msgSize];
// now you have an array of msgSize lenght
// ... do stuff...
// do not forget to release the memory when end
delete[] message;

Finally, I suggest you to re-elaborate your code because it's likely you don't need a dynamic array of chars, but just a std::string. Indeed you can use overloaded operator + in order to concatenate strings and the method std::string::c_str() to access as const char* for backward compatibility.

Upvotes: 0

Christopher Pisz
Christopher Pisz

Reputation: 4000

You would have to make your array dynamic. The size of the string is not known at compile time, but only at run time.

Also, your listing is not a minimal compilable example. I can only assume saveAs is an std::string.

The following would work:

int main()
   {
        std::string myString("My string");
        char * myCStyleString = new char[myString.size()];

        delete[] myCStyleString;
   }

because we are dynamically allocating an array there.

What are you trying to do? It looks like you just want to copy a filename into a message string. Just keep using std::string;

   int main()
   {
        std::string myString("My string");
        std::string message = "I like beans and rice with: ";
        message += myString;

        return 0;
   }

but again, I'd need a minimal compilable example to determine your goal.

Upvotes: 0

Related Questions