I have a file which contains arrays of strings representing some icons.
static constexpr char icons1[2][40] = {
"icon1_A", "icon1_B"
};
static constexpr char icons2[3][30] = {
"icon22_A", "icon2_B", "icons2_C"
};
Then I have a class that wants to be initialized with a reference to these icons.
class Display {
public:
Display(const char ** _icons) : icons(_icons), current_icon(0) {}
void print_next_icon() {
std::cout << icons[++current_icon] << std::endl;
}
private:
const char **icons;
size_t current_icon;
}
I am getting a compiler error when I try to initialize the Display class by passing it the constexpr icons:
Display i1(icons1);
Display i2(icons2);
I've tried casting it to const char**, but the compiler complains that the cast removes attributes.
The declaration here is needlessly complicated. Try and keep it simple:
static const char* icons1[] = {
"icon1_A", "icon1_B"
};
If you're passing these in as arguments and you need to know exactly how many there are it helps to have some kind of terminator:
static const char* icons1[] = {
"icon1_A", "icon1_B", nullptr
};
Where you can iterate through this list until you hit nullptr and then stop.
constexpr is used for, not surprisingly, const expressions, as in more complex expressions with operators in them and/or functions that you want to evaluate. It's not necessary here since nothing exotic is going on, this is a straight-forward const declaration.
What's worth noting here is that the memory layout of char** and char[3][40] are completely different. In the first case you have an array of pointers, where those pointers refer to arbitrary memory locations, and in the second you have what is effectively a contiguous chunk of 120 bytes, no pointers at all. This cannot be recast to the other form, it requires creating a new array of pointers.
That being said, your function assumes that these pointers will have an indefinite lifespan, which can be risky. It's almost always safer to use std::string, as in std::vector<std::string> to pass these around.
Related
I am trying to solve a coding question that requires the results be returned using a given struct. The struct is defined as:
struct Answer
{
const char* const* lastNames;
unsigned numberOfPeople;
}
Where the lastNames is a pointer to last names that are each terminated by a non-alpha char. I can not seem to find any way to convert the vector of strings that I am using to compile all the last names into a variable that I can assign to lastNames. I have tried making a single string with all the last names and assigning it with c_str() like so:
Ans->lastName = allNames.c_str(); but this gives me an error. Due to the limitations of the question I am unable to change the struct variable to anything else. How can I assign a string to a const char* const*
The structure being used effectively uses a C-style approach to defining a variable sized array of pointers to char (with const sprinkled over it). You’ll need storage for both the array of char const* as well as the entities pointed to. Here is how you could build it from a std::vector<std::string>:
std::vector<std::string> strings = somehow_compute_the_strings();
std::vector<char const*> array;
for (std::string const& s: strings) {
array.push_back(s.c_str());
}
Answer answer = { array.data(), array.size() };
Of course, you can’t return answer without the pointer inside pointing to stale data: you’d need to keep the two std::vectors alive. Potentially these two objects could be made members of an object the function is called on. To actually return an object of type Answer without a place to hold on to the std::vectors you could allocate the relevant entities and accept that the result will yield a memory leak unless the caller can clean the result up.
You can't just cast stuff. struct Answer is expecting a char**, so you are going to have to build it and keep it valid as long as the struct Answer is in use. At least they were kind enough to let us know they don't intend to modify it or mess with cleaning up the memory, since it takes "const char * const *".
#include <iostream>
#include <vector>
#include <string>
#include <assert.h>
typedef std::vector<std::string> VectorOfStrings_type;
struct Answer
{
const char* const* lastNames;
unsigned numberOfPeople;
};
class AnswerWrapper
{
private:
// construct and maintain memory so the pointers in the Answer struct will be valid
char ** lastNames;
unsigned int numberOfPeople;
public:
AnswerWrapper(const VectorOfStrings_type &input){
numberOfPeople = input.size();
// create the array of pointers
lastNames = static_cast<char**>(
malloc(numberOfPeople * sizeof(char*))
);
// create each string
for (unsigned int i = 0; i < numberOfPeople; ++i){
const std::string &name = input[i];
// allocate space
lastNames[i] = static_cast<char*>(
malloc(name.size() + 1)
);
// copy string
strncpy(lastNames[i], name.data(), name.size());
// add null terminator
lastNames[i][name.size()] = '\0';
}
}
operator Answer (){
return Answer{ lastNames, numberOfPeople };
}
~AnswerWrapper(){
// critcally important, left as an exercise
assert(0);
}
};
void SomeFunctionWhichUsesAnswer(Answer a){
// presumably you have some legacy C code here
// but here's a quick and easy demo
for (unsigned int i = 0; i < a.numberOfPeople; ++i)
std::cout << a.lastNames[i] << std::endl;
}
int main() {
// Here is your vector of strings
VectorOfStrings_type myData { "custom formatted data goes here", "and more here", "and again" };
// You must construct a buffer for the "Answer" type, which must remain in scope
AnswerWrapper temp{ myData };
// AnswerWrapper is currently in scope, so inside this function, the pointers will be valid
SomeFunctionWhichUsesAnswer(temp);
}
Also, I noticed that the strings in Answer are not referred to as null terminated. That is a separate issue you can take care of.
A const member variable can only be assigned in the constructor.
if you can add to the struct, define a constructor, and use the : lastname(value) syntax; or use the struct Answer myVar{value,number}; initialization, right where you declare your instance.
Another - ugly, dangerous, and frowned upon - alternative is a cast: (char**) lastname = value;, or in C++ syntax reinterpret_cast<char**>(lastname) = value.
If someone is teaching you either of those approaches, change the teacher.
I'm playing a bit with the C++ syntax to figure out a generalized way to keep track of an offset within a class, sort of like offsetof, but in a type-safe way and without #defines
I know that a template class can be template-parametrized with fields, besides types and constants. So I came out with this prototype:
#include <iostream>
template <typename class_type, typename field_type>
struct offsetter
{
offsetter(const char* name, field_type class_type::*field)
: name(name)
{
fprintf(stderr, "%zu\n", field);
}
const char* const name;
};
struct some_struct
{
float avg;
int min;
int max;
struct internal
{
unsigned flag;
int x;
} test;
char* name;
};
int main()
{
offsetter<some_struct, float>("%h", &some_struct::avg);
offsetter<some_struct, int>("%h", &some_struct::min);
offsetter<some_struct, char*>("%h", &some_struct::name);
offsetter<some_struct, some_struct::internal>("x", &some_struct::test);
return 0;
}
This code is actually able to print the field offset, but I'm not really sure on what I'm doing here. Indeed it feels utterly wrong to reference field without referring to an instance (foo.*field).
But it does the job: it prints the offset. My guess is that I'm hitting on some loophole though, since for instance I can't assign size_t offset = field.
I figured out I probably want something like this:
size_t offset = (&(std::declval<class_type>().*field) - &(std::declval<class_type>()))
Which however wont' work as I can't take the address of an xvalue:
taking address of xvalue (rvalue reference)
Is there any way to do this?
AFAIK there isn't a standard way of doing this. Even the standard offsetof is defined only for standard layout types.
What you are doing is UB. You are using the wrong specifier zu. There isn't much you can do with a member pointer. You can't even do pointer arithmetics on them, you can't convert to char* nor to an integer type.
Also if your assumption is that a member pointer is just an integer representing the offset from the beginning of the structure that is false, not only in theory, but also in practice. Having multiple inheritance and virtual inheritance made sure of that.
int FunctionName(const char *pValueName, const char *pValueData, long iMaxValueSize)
{
char *pDataToStore = const_cast<char *>(pValueData);
int iActualSiz = ProcessData(pDataToStore, iMaxValueSize);
...
...
}
In the upper code snippet ProcessData() function modifies the char*, which it receives as parameter. Now even after assigning pValueData into pDataToStore, after ProcessData() get executed, value of pValueData is being same as pDataToStore.
My aim is to keep intact value of pValueData which is being passed as const char*
My aim is to keep intact value of pValueData which is being passed as
const char*
That's impossible. Passing via const means it cannot be modified, except when it was originally not constant.
Example:
char *ptr1 = new char[100]; // not const
char *ptr2 = new char[100]; // not const
int i = FunctionName(ptr1, ptr2, 123);
In this case, you could technically keep the const_cast. But what for? Just change your function parameters to take char *:
int FunctionName(char *pValueName, char *pValueData, long iMaxValueSize)
{
int iActualSiz = ProcessData(pValueData, iMaxValueSize);
// ...
}
However, you most likely want to be able to pass constant strings. For example string literals:
int i = FunctionName("name", "data", 123);
String literals are unmodifiable and thus require your function to take char const *. A later attempt to modify them causes undefined behaviour.
As you can see, the error is in the general architecture and code logic. You want to modify something and at the same time you do not want to allow to modify it.
The question is: What happens with your pDataToStore when ProcessData is done with it? Does the caller of FunctionName need to be aware of the modifications? Or is it just internal business of FunctionName?
If it's just internal business of FunctionName, then you can keep its signature intact and have ProcessData modify a copy of the passed data. Here is a simplified (not exception-safe, no error checks) example:
int FunctionName(const char *pValueName, const char *pValueData, long iMaxValueSize)
{
char *copy = new char[strlen(pValueData) + 1];
strcpy(copy, pValueData):
int iActualSiz = ProcessData(copy, iMaxValueSize);
// ...
delete[] copy;
}
The nice thing is that you can now massively improve the interface of FunctionName by hiding all the low-level pointer business. In fact, why use so many pointers at all when C++ standard classes can do all the work for you?
int FunctionName(std::string const &valueName, std::string const &valueData, long maxValueSize)
{
std::vector<char> copy(valueData.begin(), valueData.end());
int actualSize = ProcessData(©[0], maxValueSize);
// ...
// no more delete[] needed here
}
The std::vector<char> automatically allocates enough memory to hold a copy of valueData, and performs the copy. It fully automatically frees the memory when it is no longer needed, even if exceptions are thrown. And ©[0] (which in C++11 can be written as copy.data()) is guaranteed to yield a pointer to the internally used data, so that low-level C functions can modify the vector's elements.
(I've also taken the chance to remove the Microsoft-style Hungarian Notation. It's a failed experiment from the 90s, and you've even used it incorrectly, supposing that a leading i is supposed to indicate an int.)
The bottom line is really:
If you need a const_cast anywhere in your code to make it compile, then somewhere else there is at least either one const missing or one too much. A const_cast always makes up for a mistake in another piece of code. It is always a workaround and never a solution designed up front.
Well I have solved the issue by creating the heap memory.
char *pDataToStore = new char[iMaxValueSize];
memcpy(pDataToStore, pValueData, iMaxValueSize*sizeof(char));
int iActualSiz = ProcessData(pDataToStore, iMaxValueSize);
...
....
delete []pDataToStore;
You have to make a difference between a const qualified type and a const qualified object.
The standard states in section 7.1.6.1: cv-qualifiers: (cv = const or volatile)
A pointer or reference to a cv-qualified type need not actually point
or refer to a cv-qualified object, but it is treated as if it does; a
const-qualified access path cannot be used to modify an object even if
the object referenced is a non-const object and can be modified
through some other access path.
If your pointer points to a non const object, the casting away will enable you to modifiy the objet, but as someone told, you are lying to the user of your function.
It your pointer points to a real const object (i.e. in const protected memory), the compiler will compile your code, but you might have a segmentation fault, typical for undefined behaviour.
Here an example, using the fact that "Ordinary string literal (...) has type “array of n const char”, where n is the size of the string (...)" (see standard, section 2.14.5):
char *my_realconst = "This is a real constant string"; // pointer does not claim that it points to const object
(*my_realconst)++; // Try to increment the first letter, will compile but will not run properly !!
So if your function ProcessData() is legacy code that is only reading the data but has forgotten to mention a const in the parameter list, your cast-away will work. If your function is however altering the data, it might work or it might fail, depending how the data poitned to was created !
So try to avoid casting const away if you are not 100% sure of what the effects will be ! Better clone your object the hard way creating a temporary object and copying the content.
I propose you a small template to handle these kind of issues easily:
template <typename T>
class Buffer {
size_t sz; // size
T* addr; // pointed
public:
Buffer(const T*source, size_t l) : sz(l), addr(new T[l]) { std::copy(source, source + l, addr); } // allocate and copy
~Buffer() { delete[]addr; } // destroy memory
operator T* () { return addr; } // convert to pointer
};
You may use your existing code almost as is:
Buffer<char> pDataToStore(pValueData, iMaxValueSize); // create the automatic buffer
int iActualSiz = ProcessData(pDataToStore, iMaxValueSize); // automatic use of pointer to buffer
cout << "modified copy: " << pDataToStore << endl;
cout << "original: " << pValueData << endl;
The buffer will be automatically released once pDataToStore is no longer in scope.
If you have similar issues with wchar_t buffers or anything else, it will work as well.
For explanations on the evil of casting away const, see my other answer
My actual question is it really possible to compare values contained in two void pointers, when you actually know that these values are the same type? For example int.
void compVoids(void *firstVal, void *secondVal){
if (firstVal < secondVal){
cout << "This will not make any sense as this will compare addresses, not values" << endl;
}
}
Actually I need to compare two void pointer values, while outside the function it is known that the type is int. I do not want to use comparison of int inside the function.
So this will not work for me as well: if (*(int*)firstVal > *(int*)secondVal)
Any suggestions?
Thank you very much for help!
In order to compare the data pointed to by a void*, you must know what the type is. If you know what the type is, there is no need for a void*. If you want to write a function that can be used for multiple types, you use templates:
template<typename T>
bool compare(const T& firstVal, const T& secondVal)
{
if (firstVal < secondVal)
{
// do something
}
return something;
}
To illustrate why attempting to compare void pointers blind is not feasible:
bool compare(void* firstVal, void* secondVal)
{
if (*firstVal < *secondVal) // ERROR: cannot dereference a void*
{
// do something
}
return something;
}
So, you need to know the size to compare, which means you either need to pass in a std::size_t parameter, or you need to know the type (and really, in order to pass in the std::size_t parameter, you have to know the type):
bool compare(void* firstVal, void* secondVal, std::size_t size)
{
if (0 > memcmp(firstVal, secondVal, size))
{
// do something
}
return something;
}
int a = 5;
int b = 6;
bool test = compare(&a, &b, sizeof(int)); // you know the type!
This was required in C as templates did not exist. C++ has templates, which make this type of function declaration unnecessary and inferior (templates allow for enforcement of type safety - void pointers do not, as I'll show below).
The problem comes in when you do something (silly) like this:
int a = 5;
short b = 6;
bool test = compare(&a, &b, sizeof(int)); // DOH! this will try to compare memory outside the bounds of the size of b
bool test = compare(&a, &b, sizeof(short)); // DOH! This will compare the first part of a with b. Endianess will be an issue.
As you can see, by doing this, you lose all type safety and have a whole host of other issues you have to deal with.
It is definitely possible, but since they are void pointers you must specify how much data is to be compared and how.
The memcmp function may be what you are looking for. It takes two void pointers and an argument for the number of bytes to be compared and returns a comparison. Some comparisons, however, are not contingent upon all of the data being equal. For example: comparing the direction of two vectors ignoring their length.
This question doesn't have a definite answer unless you specify how you want to compare the data.
You need to dereference them and cast, with
if (*(int*) firstVal < *(int*) secondVal)
Why do you not want to use the int comparison inside the function, if you know that the two values will be int and that you want to compare the int values that they're pointing to?
You mentioned a comparison function for comparing data on inserts; for a comparison function, I recommend this:
int
compareIntValues (void *first, void *second)
{
return (*(int*) first - *(int*) second);
}
It follows the convention of negative if the first is smaller, 0 if they're equal, positive if the first is larger. Simply call this function when you want to compare the int data.
yes. and in fact your code is correct if the type is unsigned int. casting int values to void pointer is often used even not recommended.
Also you could cast the pointers but you have to cast them directly to the int type:
if ((int)firstVal < (int)secondVal)
Note: no * at all.
You may have address model issues doing this though if you build 32 and 64 bits. Check the intptr_t type that you could use to avoid that.
if ((intptr_t)firstVal < (intptr_t)secondVal)
I do understand that functions should not return references to automatic variables.
However I just wanted to understand where constant objects are stored i.e if it is stored in the memory section along with static global variables .
Here is the code on Visual studio 8 . It looks like const objects are stored as auto variables. Am i assuming things right or is it implementation specific or does it depend on whether the constructor is trivial ?
Would be really great if someone could explain why each of these cases behave the way they do.
//here i'm intentionally returning a ptr to local const ptr hope the syntax is right
const char* const* get_const_char_ptr() {
const char * const ptr = "downontheupside";
return &ptr;
}
const int& get_const_int() {
const int magic_number = 20;
return magic_number;
}
const string& get_const_string() {
const string str("superunknown");
return str;
}
const string* get_const_string_ptr() {
const string str("louderthanlove");
return &str;
}
int main() {
//case1
const int &i = get_const_int();
cout<<"case1:"<<i<<endl;
//case 2
const char * const* c =get_const_char_ptr();
cout<<"case2:"<<*c<<endl;
//case3
const string &str = get_const_string();
//this crashes
//cout<<"case3:"<<str<<endl;
return 1;
}
const does not change where things are stored it's a keyword to tell the compiler to prevent variables or functions from modifying things. Example:
std::string myNormalStr("Hello");
const std::string myConstStr("Don't Change Me");
myNormalStr = myConstStr; // this is ok
myConstStr = myNormalStr; // this will give you a compile error
That's a super simplistic example but the same thing applies to const objects which are passed into functions, returned from functions, or if the function itself is const.
Here's a great article by Herb Sutter on all the correct ways to use the const keyword.
Edit:
Currently there is almost no reason to use the auto keyword as everything is implicitly auto within it's scope. This keyword is a storage class specifier for an automatic variable.
However the auto keyword is changing as part of the new C++ standard in progress but is supported already by Visual Studio 2010 and some other compilers in it's new glorious form. It can be used like so in C++0x:
std::vector<int> numbers;
for (std::vector<int>::const_iterator itr(numbers.begin());
itr != numbers.end(); ++itr)
{
// do something with each iterated element
}
// compiler auto deduces from rvalue
// and determines that you want a
// std::vector<int>::const_iterator type
for (auto itr = numbers.cbegin();
itr != numbers.cend(); ++itr)
{
// do something with each iterated element
}
Constant objects allocated within a function are just like any other automatic variable; they just have const types. Global (and class-static) variables are slightly different: some constants can be placed in read-only parts of the executable file and then just copied into memory. That is used for things like string and integer constants; I do not believe it is used for anything with a nontrivial constructor.
Absolutely everything about where something is stored is implementation specific. Never forget that. With that caveat, here are some typical rules.
Automatic variables are either stored on the stack or in a register. Doesn't matter if they're const or not.
Static variables are stored in program memory. There may be multiple blocks of program memory, some read-only and some not. Declaring a variable const may affect which block something is stored in.
Variables allocated with new will be on the heap. Doesn't matter if it's const or not.