C++ Constant anonymous instance with aggregate initialization - c++

Basically Im wanting to fetch a pointer of a constant and anonymous object, such as an instance of a class, array or struct that is inialised with T {x, y, z...}. Sorry for my poor skills in wording.
The basic code that Im trying to write is as follows:
//Clunky, Im sure there is an inbuilt class that can replace this, any information would be a nice addition
template<class T> class TerminatedArray {
public:
T* children;
int length;
TerminatedArray(const T* children) {
this->children = children;
length = 0;
while ((unsigned long)&children[length] != 0)
length++;
}
TerminatedArray() {
length = 0;
while ((unsigned long)&children[length] != 0)
length++;
}
const T get(int i) {
if (i < 0 || i >= length)
return 0;
return children[i];
}
};
const TerminatedArray<const int> i = (const TerminatedArray<const int>){(const int[]){1,2,3,4,5,6,0}};
class Settings {
public:
struct Option {
const char* name;
};
struct Directory {
const char* name;
TerminatedArray<const int> const children;
};
const Directory* baseDir;
const TerminatedArray<const Option>* options;
Settings(const Directory* _baseDir, const TerminatedArray<const Option> *_options);
};
//in some init method's:
Settings s = Settings(
&(const Settings::Directory){
"Clock",
(const TerminatedArray<const int>){(const int[]){1,2,0}}
},
&(const TerminatedArray<const Settings::Option>){(const Settings::Option[]){
{"testFoo"},
{"foofoo"},
0
}}
);
The code that I refer to is at the very bottom, the definition of s. I seem to be able to initialize a constant array of integers, but when applying the same technique to classes, it fails with:
error: taking address of temporary [-fpermissive]
I don't even know if C++ supports such things, I want to avoid having to have separate const definitions dirtying and splitting up the code, and instead have them clean and anonymous.
The reason for wanting all these definitions as constants is that Im working on an Arduino project that requires efficient balancing of SRAM to Flash. And I have a lot of Flash to my disposal.
My question is this. How can I declare a constant anonymous class/struct using aggregate initialization?

The direct (and better) equivalent to TerminatedArray is std::initializer_list:
class Settings {
public:
struct Option {
const char* name;
};
struct Directory {
const char* name;
std::initializer_list<const int> const children;
};
const Directory* baseDir;
const std::initializer_list<const Option>* options;
Settings(const Directory& _baseDir, const std::initializer_list<const Option>& _options);
};
//in some init method's:
Settings s = Settings(
{
"Clock",
{1,2,0}
},
{
{"testFoo"},
{"foofoo"}
}
);
https://godbolt.org/z/8t7j0f
However, this will almost certainly have lifetime issues (which the compiler tried to warn you about with "taking address of temporary"). If you want to store a (non-owning) pointer (or reference) then somebody else should have ownership of the object. But when initializing with temporary objects like this, nobody else does. The temporaries die at the end of the full expression, so your stored pointers now point to dead objects. Fixing this is a different matter (possibly making your requirements conflicting).
Somewhat relatedly, I'm not sure whether storing a std::initializer_list as class member is a good idea might. But it's certainly the thing you can use as function parameter to make aggregate initialization nicer.

&children[length] != 0 is still true or UB.
If you don't want to allocate memory, you might take reference to existing array:
class Settings {
public:
struct Option {
const char* name;
};
struct Directory {
const char* name;
std::span<const int> const children;
};
const Directory baseDir;
const std::span<const Option> options;
Settings(Directory baseDir, span<const Option> options);
};
//in some method:
const std::array<int, 3> ints{{1,2,0}};
const std::array<Settings::Option> options{{"testFoo"}, {"foofoo"}};
Settings s{"Clock", {ints}}, options};

First, you're not aggregate-initializing anything. This is uniform initialization and you're calling constructors instead of directly initializing members. This is because your classes have user-defined constructors, and classes with constructors can't be aggregate-initialized.
Second, you're not really able to "initialize a constant array of integers". It merely compiles. Trying to run it gives undefined behavior - in my case, trying to construct i goes into an infinite search for element value 0.
In C++, there's values on the stack, there's values on the heap and there's temporary values (I genuinely apologize to anyone who knows C++ for this statement).
Values on the heap have permanent addresses which you can pass around freely.
Values on the stack have temporary addresses which are valid until
the end of the block.
Temporary values either don't have addresses
(as your compiler warns you) or have a valid address for the duration
of the expression they're used for.
You're using such a temporary to initialize i, and trying to store and use the address of a temporary. This is an error and to fix it you can create your "temporary" array on the stack if you don't plan to use i outside of the block where your array will be.
Or you can create your array on the heap, use its address to initialize i, and remember to explicitly delete your array when you're done with it.
I recommend reading https://isocpp.org/faq and getting familiar with lifetime of variables and memory management before attempting to fix this code. It should give you a much better idea of what you need to do to make your code do what you want it to do.
Best of luck.

Related

Save reference to void pointer in a vector during loop iteration

Guys I have a function like this (this is given and should not be modified).
void readData(int &ID, void*&data, bool &mybool) {
if(mybool)
{
std::string a = "bla";
std::string* ptrToString = &a;
data = ptrToString;
}
else
{
int b = 9;
int* ptrToint = &b;
data = ptrToint;
}
}
So I want to use this function in a loop and save the returned function parameters in a vector (for each iteration).
To do so, I wrote the following struct:
template<typename T>
struct dataStruct {
int id;
T** data; //I first has void** data, but would not be better to
// have the type? instead of converting myData back
// to void* ?
bool mybool;
};
my main.cpp then look like this:
int main()
{
void* myData = nullptr;
std::vector<dataStruct> vec; // this line also doesn't compile. it need the typename
bool bb = false;
for(int id = 1 ; id < 5; id++) {
if (id%2) { bb = true; }
readData(id, myData, bb); //after this line myData point to a string
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
}
}
Or is there a better way to do that without template? I used c++11 (I can't use c++14)
The function that you say cannot be modified, i.e. readData() is the one that should alert you!
It causes Undefined Behavior, since the pointers are set to local variables, which means that when the function terminates, then these pointers will be dangling pointers.
Let us leave aside the shenanigans of the readData function for now under the assumption that it was just for the sake of the example (and does not produce UB in your real use case).
You cannot directly store values with different (static) types in a std::vector. Notably, dataStruct<int> and dataStruct<std::string> are completely unrelated types, you cannot store them in the same vector as-is.
Your problem boils down to "I have data that is given to me in a type-unsafe manner and want to eventually get type-safe access to it". The solution to this is to create a data structure that your type-unsafe data is parsed into. For example, it seems that you inteded for your example data to have structure in the sense that there are pairs of int and std::string (note that your id%2 is not doing that because the else is missing and the bool is never set to false again, but I guess you wanted it to alternate).
So let's turn that bunch of void* into structured data:
std::pair<int, std::string> readPair(int pairIndex)
{
void* ptr;
std::pair<int, std::string> ret;
// Copying data here.
readData(2 * pairIndex + 1, ptr, false);
ret.first = *reinterpret_cast<int*>(ptr);
readData(2 * pairIndex + 2, ptr, true);
ret.second = *reinterpret_cast<std::string*>(ptr);
}
void main()
{
std::vector<std::pair<int, std::string>> parsedData;
parsedData.push_back(readPair(0));
parsedData.push_back(readPair(1));
}
Demo
(I removed the references from the readData() signature for brevity - you get the same effect by storing the temporary expressions in variables.)
Generally speaking: Whatever relation between id and the expected data type is should just be turned into the data structure - otherwise you can only reason about the type of your data entries when you know both the current ID and this relation, which is exactly something you should encapsulate in a data structure.
Your readData isn't a useful function. Any attempt at using what it produces gives undefined behavior.
Yes, it's possible to do roughly what you're asking for without a template. To do it meaningfully, you have a couple of choices. The "old school" way would be to store the data in a tagged union:
struct tagged_data {
enum { T_INT, T_STR } tag;
union {
int x;
char *y;
} data;
};
This lets you store either a string or an int, and you set the tag to tell you which one a particular tagged_data item contains. Then (crucially) when you store a string into it, you dynamically allocate the data it points at, so it will remain valid until you explicitly free the data.
Unfortunately, (at least if memory serves) C++11 doesn't support storing non-POD types in a union, so if you went this route, you'd have to use a char * as above, not an actual std::string.
One way to remove (most of) those limitations is to use an inheritance-based model:
class Data {
public:
virtual ~Data() { }
};
class StringData : public Data {
std::string content;
public:
StringData(std::string const &init) : content(init) {}
};
class IntData : public Data {
int content;
public:
IntData(std::string const &init) : content(init) {}
};
This is somewhat incomplete, but I think probably enough to give the general idea--you'd have an array (or vector) of pointers to the base class. To insert data, you'd create a StringData or IntData object (allocating it dynamically) and then store its address into the collection of Data *. When you need to get one back, you use dynamic_cast (among other things) to figure out which one it started as, and get back to that type safely. All somewhat ugly, but it does work.
Even with C++11, you can use a template-based solution. For example, Boost::variant, can do this job quite nicely. This will provide an overloaded constructor and value semantics, so you could do something like:
boost::variant<int, std::string> some_object("input string");
In other words, it's pretty what you'd get if you spent the time and effort necessary to finish the inheritance-based code outlined above--except that it's dramatically cleaner, since it gets rid of the requirement to store a pointer to the base class, use dynamic_cast to retrieve an object of the correct type, and so on. In short, it's the right solution to the problem (until/unless you can upgrade to a newer compiler, and use std::variant instead).
Apart from the problem in given code described in comments/replies.
I am trying to answer your question
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
Before that you need to modify vec definition as following
vector<dataStruct<void>> vec;
Now you can simple push element in vector
vec.push_back({id, &mydata, bb});
i have tried to modify your code so that it can work
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
struct dataStruct
{
int id;
T** data;
bool mybool;
};
void readData(int &ID, void*& data, bool& mybool)
{
if (mybool)
{
data = new string("bla");
}
else
{
int b = 0;
data = &b;
}
}
int main ()
{
void* mydata = nullptr;
vector<dataStruct<void>> vec;
bool bb = false;
for (int id = 0; id < 5; id++)
{
if (id%2) bb = true;
readData(id, mydata, bb);
vec.push_back({id, &mydata, bb});
}
}

Initialise array of struct with const fields which don't have a default constructor

I want to define an array of structs, but this is not working because it has a const field without default constructor.
Struct is part of an SDK and looks like following:
struct SParametricParamDef
{
const TXString fUniversalName;
SResString fLocalizedName;
const TXString fDefaultImperial;
const TXString fDefaultMetric;
EFieldStyle fFieldStyle;
short fChoicesChcID;
};
TXString does not have a default constructor. So following is failing:
SParametricParamDef *arrParams = new SParametricParamDef[size]; // <= throws compile time exception
for (int i = 0; i < size; i++)
{
arrParams[i] = params[i].def; // <= also throws an exception, because operator = is not available
}
Is there some way to solve this? I need an SParametricParamDef* as a result, because this array is used in the SDK again...
Info
In an old SDK version, const TXSTring was const char* and back then I did not have problems... Now I need to adjust my code to work with the new structures...
The error you get is not primarily about operator = but about the fact that you default-constructed an object with const members. This will render them immutable and any attempt to modify them, as you are trying in the loop, must fail.
Fortunately, you can use emplace_back to initialize the SParametricParamDef objects right inside the vector without taking the indirection of default-construction and assignment:
std::vector<SParametricParamDef> arrParams;
for(std::size_t n = 0; n < size; ++n) {
arrParams.emplace_back(params[n].def);
}
This should minimize the amount of copying and comes without the need to modify the struct definition.
The compiler is telling you that you are asking for a TXString to be created without directing how it can be initialised. It is difficult to know how to address the problem of creating a TXString object since you haven't given a list of the constructors for the class, but as it stands a change would need to be made to the code you've given. Some ways of solving this are as follows:
The most obvious is to add a default constructor for SParametricParamDef which initialises the TXString objects:
struct SParametricParamDef
{
SParametricParamDef() : fUniversalName(...), ... {}
...
Another approach, given that the variables are const might be to make them const static
Say, for simplicity's sake, that the TXString object was as follows:
struct TXString{
TXString(char a) : _a(a) {}
char _a;
};
You could then change your declaration of SParametricParamDef to:
struct SParametricParamDef
{
const static TXString fUniversalName;
...
and then define fUniversalName in your implementation file as follows:
const TXString SParametricParamDef::fUniversalName('D');
Another way might be to wrap a TXString object in another object that does have a default constructor:
struct TXStringWrapper {
TXStringWrapper() : _s(...) {} // [1]
const TXString& get() { return _s; }
private:
TXString _s;
}
At [1], you create the TXString in whatever specific, non-default way that you care.
That looks like an example for using a placement new:
SParametricParamDef *arrParams = (SParametricParamDef *) new char[size * sizeof(*arrParams)];
for (int i = 0; i < size; i++)
{
// constructs an object in a pre-allocated memory
new(arrParams+1) SParametricParamDef(params[i].def);
}
You should explicitely call a destructor if it is not trivial before freeing the array:
for (int i = 0; i < size; i++)
{
~SParametricParamDef(arrParams+1);
}
delete[] ((char *) arrParams);
This is rather old fashioned because it mimics the initialization of structs in C, but it is the only way I know to build an array of objects that only have non trivial constructors (AFAIK, the std::vector way requires copyable or movable objects)

How to get "read access" to the private member?

What's the best course of action in C++ to take in the following situation?
My class has some double pointer as a private member:
class A
{
private:
int** data;
//...//
public:
int** get_data () const { return data; };
//...//
}
And sometimes I'd like to check the values inside this pointer and change them. And there's some get function get_data for this purpose:
A* obj = new A();
//...//
int** data_from_A = obj->get_data();
// some manipulations with data_from_A pointer
But what if I want to be confident that nothing won't change it in the further usage?
How is it better to get only the "read access" to the data pointer?
Of course, we can make the data pointer public, but in this case it can be changed from the outside, that is unacceptable...
Thanks!
In C++, raw pointers, and especially pointer arithmetics, should only be used buried deep deep within a class that utilizes them for high performance computing.
The only reason to give something like a pointer to an array to the outside is that you use some other code that would be tedious to rewrite, like a highly optimized solver written by somebody who is used to writing C style code (with the solver actually being in C maybe).
If not, go with a class from the standard library, like std::vector (dynamic), std::array (static) or std::list (linked).
This would transform your code to something like
private:
vector<vector<int> > data;
public:
const vector<vector<int> >& get_data() const { return data; }
Simple as that, one const totally suffices, none more required for sub-vectors as it would be with a raw array.
Another way would be to go with
const int& get_data(const size_t i, const size_t j) const { return data[i][j]; }
which would work even with your current code.
For the vector, remember that if you want to use it for a while, then you have to get it with
const vector<vector<int> >& data = myClass.get_data();
and not with either of those
vector<vector<int> >& data = myClass.get_data(); //compile error
vector<vector<int> > data = myClass.get_data(); //works but unnecessarily copies the data
The answer is to make "data" private and make the function which sets it up a "friend". Then the member is protected from access, except within your special function.
However friend functions are usually a sign of poor design, so you will probably want to look at refactoring to eliminate the need for this.

How to use the same POD in const and non-const contexts?

The initial problem is that I have some data to save and retrieve from plate and would like to use a helper struct in the following way:
// this is how I want to use my struct for saving
void safeData()
{
Data data;
data.name = getNameToSave(); // returns const char*
save(data);
}
// ... and in the same way for writing.
void readData()
{
Data data;
read(data);
use(data);
}
... whereas
struct Data
{
const char* name;
// potentially many more data members
}
I'm bound to (const) char* instead of std::string for now because this should be used with legacy code. Unfortunately this will bring up a constness problem:
void read(Data& data)
{
// initial legacy free
free(data.name); // warning: can't convert from const char* to void*
// fill with some data
data.name = getNameFromPlate();
}
So the thing is this: Since my data retrieval methods for reading like getNameFromSomewhere returns const char* I'm bound to making my struct members const, too. This however clashes with write-usage because in this case they must be non-const. What is the best and cleanest way to work around this?
The cleanest way is for the Data struct to own the name data. So when you assign to it you should allocate memory and do a memcpy. This is the only way to make sure that a) you don't leak memory b) the data is not freed before you are done with it and c) data is not changed by other processes in the mean time.
Since you do a copy anyway, you can probably make it more manageable by using std::string instead of const char*. When you assign for const char*, std::string will do the copy for you and you can get a const char* back with c_str(), so that you can still work with the legacy architecture. You don't have to do the switch but will make it easier to manage in the long run.
You have not only a problem of constness, but also a problem of ownership. Except if the API states that the return value of getNameToSave() has to be freed by caller after use, you should not free it. While when you read it from a file, you must free it.
So the simpler way is to always use a local copy that you consistently free after use. As you are required to use old const char * instead of std::string you'd better keep using the good old C library function. Here the best function is strdup that automagically allocate memory and copy old string into it.
An alternative way would be to store the status of the member Data::name in a boolean member :
struct Data
{
const char* name;
bool dyn; // must be freed if true
// potentially many more data members
}
You can then safely use:
if (data.dyn && (data.name != nullptr)) {
free(const_cast<char *>(data.name);
}

Pointers to objects in C++

I am trying to get the hang of C++ pointers and objects, through a small project implementing a simple Vehicle Routing Problem. Even though my code is currently working, I can't shake the feeling that my approach is completely wrong. What bugs me, are snippets of code such as :
std::map<const Route*, double>::iterator it = quantities.begin();
if ((*(*(it->first)).getDestination()).getDemand() > (*(*(it->first)).getDeparture()).getSupply())
The pointer hell situation in the if condition is the result of the get methods returning pointers to already created objects. The methods being called are :
const Departure* Route::getDeparture() const {
return departure;
};
const Destination* Route::getDestination() const {
return destination;
};
and
int Destination::getDemand() const {
return demand;
};
int Departure::getSupply() const {
return supply;
};
Am I completely off track here, am i missing something or is this type of situtation something normal?
To increase readability you can change *s to ->:
if(it->first->getDestination()->getDemand() > it->first->getDeparture()->getSupply())
Also, if you aren't going to give up ownership of that object (and you aren't, in this case) it is better to return by const reference:
const Departure& Route::getDeparture() const {
return *departure;
};
and use ., not ->:
if(it->first->getDestination().getDemand() > it->first->getDeparture().getSupply())
instead of (*p).x write p->x.