Using 'memcpy()' inside a class with a union - c++

I have a class foo that manages data using small buffer optimization (SBO).
When size < 16, the data is held locally (in buffer), otherwise it is stored on the heap, with reserved holding the allocated space.
class foo {
static const int sbo_size = 16;
long size = 0;
char *ptr;
union {
char buffer[sbo_size];
long reserved;
};
public:
foo()
{
for (int i = 0; i < sbo_size; ++i)
buffer[i] = 0;
}
void clone(const foo &f)
{
// release 'ptr' if necessary
if (f.size < sbo_size)
{
memcpy(this, &f, sizeof(foo));
ptr = buffer;
} else
{
// handle non-sbo case
}
}
};
Question about clone():
With the SBO case, it may not be clear for the compiler that union::buffer will be used.
is it correct to use memcpy and set ptr accordingly?

If you can use C++17, I would side-step any potential type-punning problems by using std::variant in place of a union.
Although this uses a small amount of storage internally to keep track of the current type it contains, it's probably a win overall as your ptr variable can disappear (although that should be inside your union anyway).
It's also typesafe, which a union is not (because std::get will throw if the variant doesn't contain the desired type) and will keep track of the type of data it contains simply by assigning to it.
The resulting class fragment might look something like this (no doubt this code can be improved):
class foo
{
private:
static const size_t sbo_size = 16;
using small_buf = std::array <char, sbo_size>;
size_t size = 0;
std::variant <small_buf, char *> buf = { };
public:
void clone (const foo &f)
{
char **bufptr = std::get_if <char *> (&buf);
if (bufptr)
delete [] *bufptr;
size = f.size;
if (size < sbo_size)
buf = std::get <small_buf> (f.buf);
else
{
buf = new char [size];
std::memcpy (std::get <char *> (buf), std::get <char *> (f.buf), size);
}
}
};
Notes:
You will see that I've used std::array instead of a C-style array because std:array has lots of nice features that C-style arrays do not
Why clone and not a copy constructor?
if you want foo to have an empty state (after being default constructed, say), then you can look into the strangely named std::monostate.
For raw storage, std::byte is probably to be preferred over char.
Fully worked example here.
Edit: To answer the question as posed, I am no language lawyer but it seems to me that, inside clone, the compiler has no clue what the active member of f might be as it has, in effect, been parachuted in from outer space.
In such circumstances, I would expect compiler writers to play it safe and set the active member of the union to "don't know" until some concrete information comes along. But (and it's a big but), I wouldn't like to bet my shirt on that. It's a complex job and compiler writers do make mistakes.
So, in a spirit of sharing, here's a slightly modified version of your original code which fixes that. I've also moved ptr inside your union since it clearly belongs there:
class foo {
static const int sbo_size = 16;
long size = 0;
union {
std::array <char, sbo_size> buffer; // changing this
char *ptr;
long reserved;
};
public:
foo()
{
for (int i = 0; i < sbo_size; ++i)
buffer[i] = 0;
}
void clone(const foo &f)
{
// release 'ptr' if necessary
if (f.size < sbo_size)
{
buffer = f.buffer; // lets me do this
ptr = buffer.data ();
} else
{
// handle non-sbo case
}
}
};
So you can see, by using std::array for buffer (rather than one of those hacky C-style arrays), you can directly assign to it (rather than having to resort to memcpy) and the compiler will then make that the active member of your union and you should be safe.
In conclusion, the question is actually rather meaningless since one shouldn't (ever) need to write code like that. But no doubt someone will immediately come up with something that proves me wrong.

Related

C++ Constant anonymous instance with aggregate initialization

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.

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});
}
}

C++ Access memory which isn't part of the object itself

It sounds weird, I guess, but I'm creating some low-level code for a hardware device. Dependend on specific conditions I need to allocate more space than the actual struct needs, store informations there and pass the address of the object itself to the caller.
When the user is deallocating such an object, I need to read these informations before I actually deallocate the object.
At the moment, I'm using simple pointer operations to get the addresses (either of the class or the extra space). However, I tought it would be more understandable if I do the pointer arithmetics in member functions of an internal (!) type. The allocator, which is dealing with the addresses, is the only one who know's about this internal type. In other words, the type which is returned to the user is a different one.
The following example show's what I mean:
struct foo
{
int& get_x() { return reinterpret_cast<int*>(this)[-2]; }
int& get_y() { return reinterpret_cast<int*>(this)[-1]; }
// actual members of foo
enum { size = sizeof(int) * 2 };
};
int main()
{
char* p = new char[sizeof(foo) + foo::size];
foo* bar = reinterpret_cast<foo*>(p + foo::size);
bar->get_x() = 1;
bar->get_y() = 2;
std::cout << bar->get_x() << ", " << bar->get_y() << std::endl;
delete p;
return 0;
}
Is it arguable to do it in that way?
It seems needlessly complex to do it this way. If I were to implement something like this, I would take a simpler approach:
#pragma pack(push, 1)
struct A
{
int x, y;
};
struct B
{
int z;
};
#pragma pack(pop)
// allocate space for A and B:
unsigned char* data = new char[sizeof(A) + sizeof(B)];
A* a = reinterpret_cast<A*>(data);
B* b = reinterpret_cast<B*>(a + 1);
a->x = 0;
a->y = 1;
b->z = 2;
// When deallocating:
unsigned char* address = reinterpret_cast<unsigned char*>(a);
delete [] address;
This implementation is subtly different, but much easier (in my opinion) to understand, and doesn't rely on intimate knowledge of what is or is not present. If all instances of the pointers are allocated as unsigned char and deleted as such, the user doesn't need to keep track of specific memory addresses aside from the first address in the block.
The very straightforward idea: wrap your extra logic in a factory which will create objects for you and delete them smart way.
You can also create the struct as a much larger object, and use a factory function to return an instance of the struct, but cast to a much smaller object that would basically act as the object's handle. For instance:
struct foo_handle {};
struct foo
{
int a;
int b;
int c;
int d;
int& get_a() { return a; }
int& get_b() { return b; }
//...more member methods
//static factory functions to create and delete objects
static foo_handle* create_obj() { return new foo(); }
static void delete_obj(foo_handle* obj) { delete reinterpret_cast<foo*>(obj); }
};
void another_function(foo_handle* masked_obj)
{
foo* ptr = reinterpret_cast<foo*>(masked_obj);
//... do something with ptr
}
int main()
{
foo_handle* handle = foo::create_obj();
another_function(handle);
foo::delete_obj(handle);
return 0;
}
Now you can hide any extra space you may need in your foo struct, and to the user of your factory functions, the actual value of the pointer doesn't matter since they are mainly working with an opaque handle to the object.
It seems your question is a candidate for the popular struct hack.
Is the "struct hack" technically undefined behavior?

On what platforms will this crash, and how can I improve it?

I've written the rudiments of a class for creating dynamic structures in C++. Dynamic structure members are stored contiguously with (as far as my tests indicate) the same padding that the compiler would insert in the equivalent static structure. Dynamic structures can thus be implicitly converted to static structures for interoperability with existing APIs.
Foremost, I don't trust myself to be able to write Boost-quality code that can compile and work on more or less any platform. What parts of this code are dangerously in need of modification?
I have one other design-related question: Is a templated get accessor the only way of providing the compiler with the requisite static type information for type-safe code? As it is, the user of dynamic_struct must specify the type of the member they are accessing, whenever they access it. If that type should change, all of the accesses become invalid, and will either cause spectacular crashes—or worse, fail silently. And it can't be caught at compile time. That's a huge risk, and one I'd like to remedy.
Example of usage:
struct Test {
char a, b, c;
int i;
Foo object;
};
void bar(const Test&);
int main(int argc, char** argv) {
dynamic_struct<std::string> ds(sizeof(Test));
ds.append<char>("a") = 'A';
ds.append<char>("b") = '2';
ds.append<char>("c") = 'D';
ds.append<int>("i") = 123;
ds.append<Foo>("object");
bar(ds);
}
And the code follows:
//
// dynamic_struct.h
//
// Much omitted for brevity.
//
/**
* For any type, determines the alignment imposed by the compiler.
*/
template<class T>
class alignment_of {
private:
struct alignment {
char a;
T b;
}; // struct alignment
public:
enum { value = sizeof(alignment) - sizeof(T) };
}; // class alignment_of
/**
* A dynamically-created structure, whose fields are indexed by keys of
* some type K, which can be substituted at runtime for any structure
* with identical members and packing.
*/
template<class K>
class dynamic_struct {
public:
// Default maximum structure size.
static const int DEFAULT_SIZE = 32;
/**
* Create a structure with normal inter-element padding.
*/
dynamic_struct(int size = DEFAULT_SIZE) : max(size) {
data.reserve(max);
} // dynamic_struct()
/**
* Copy structure from another structure with the same key type.
*/
dynamic_struct(const dynamic_struct& structure) :
members(structure.members), max(structure.max) {
data.reserve(max);
for (iterator i = members.begin(); i != members.end(); ++i)
i->second.copy(&data[0] + i->second.offset,
&structure.data[0] + i->second.offset);
} // dynamic_struct()
/**
* Destroy all members of the structure.
*/
~dynamic_struct() {
for (iterator i = members.begin(); i != members.end(); ++i)
i->second.destroy(&data[0] + i->second.offset);
} // ~dynamic_struct()
/**
* Get a value from the structure by its key.
*/
template<class T>
T& get(const K& key) {
iterator i = members.find(key);
if (i == members.end()) {
std::ostringstream message;
message << "Read of nonexistent member \"" << key << "\".";
throw dynamic_struct_access_error(message.str());
} // if
return *reinterpret_cast<T*>(&data[0] + i->second.offset.offset);
} // get()
/**
* Append a member to the structure.
*/
template<class T>
T& append(const K& key, int alignment = alignment_of<T>::value) {
iterator i = members.find(key);
if (i != members.end()) {
std::ostringstream message;
message << "Add of already existing member \"" << key << "\".";
throw dynamic_struct_access_error(message.str());
} // if
const int modulus = data.size() % alignment;
const int delta = modulus == 0 ? 0 : sizeof(T) - modulus;
if (data.size() + delta + sizeof(T) > max) {
std::ostringstream message;
message << "Attempt to add " << delta + sizeof(T)
<< " bytes to struct, exceeding maximum size of "
<< max << ".";
throw dynamic_struct_size_error(message.str());
} // if
data.resize(data.size() + delta + sizeof(T));
new (static_cast<void*>(&data[0] + data.size() - sizeof(T))) T;
std::pair<iterator, bool> j = members.insert
({key, member(data.size() - sizeof(T), destroy<T>, copy<T>)});
if (j.second) {
return *reinterpret_cast<T*>(&data[0] + j.first->second.offset);
} else {
std::ostringstream message;
message << "Unable to add member \"" << key << "\".";
throw dynamic_struct_access_error(message.str());
} // if
} // append()
/**
* Implicit checked conversion operator.
*/
template<class T>
operator T&() { return as<T>(); }
/**
* Convert from structure to real structure.
*/
template<class T>
T& as() {
// This naturally fails more frequently if changed to "!=".
if (sizeof(T) < data.size()) {
std::ostringstream message;
message << "Attempt to cast dynamic struct of size "
<< data.size() << " to type of size " << sizeof(T) << ".";
throw dynamic_struct_size_error(message.str());
} // if
return *reinterpret_cast<T*>(&data[0]);
} // as()
private:
// Map from keys to member offsets.
map_type members;
// Data buffer.
std::vector<unsigned char> data;
// Maximum allowed size.
const unsigned int max;
}; // class dynamic_struct
There's nothing inherently wrong with this kind of code. Delaying type-checking until runtime is perfectly valid, although you will have to work hard to defeat the compile-time type system. I wrote a homogenous stack class, where you could insert any type, which functioned in a similar fashion.
However, you have to ask yourself- what are you actually going to be using this for? I wrote a homogenous stack to replace the C++ stack for an interpreted language, which is a pretty tall order for any particular class. If you're not doing something drastic, this probably isn't the right thing to do.
In short, you can do it, and it's not illegal or bad or undefined and you can make it work - but you only should if you have a very desperate need to do things outside the normal language scope. Also, your code will die horrendously when C++0x becomes Standard and now you need to move and all the rest of it.
The easiest way to think of your code is actually a managed heap of a miniature size. You place on various types of object.. they're stored contiguously, etc.
Edit: Wait, you didn't manage to enforce type safety at runtime either? You just blew compile-time type safety but didn't replace it? Let me post some far superior code (that is somewhat slower, probably).
Edit: Oh wait. You want to convert your dynamic_struct, as the whole thing, to arbitrary unknown other structs, at runtime? Oh. Oh, man. Oh, seriously. What. Just no. Just don't. Really, really, don't. That's so wrong, it's unbelievable. If you had reflection, you could make this work, but C++ doesn't offer that. You can enforce type safety at runtime per each individual member using dynamic_cast and type erasure with inheritance. Not for the whole struct, because given a type T you can't tell what the types or binary layout is.
I think the type-checking could be improved. Right now it will reinterpret_cast itself to any type with the same size.
Maybe create an interface to register client structures at program startup, so they may be verified member-by-member — or even rearranged on the fly, or constructed more intelligently in the first place.
#define REGISTER_DYNAMIC_STRUCT_CLIENT( STRUCT, MEMBER ) \
do dynamic_struct::registry< STRUCT >() // one registry obj per client type \
.add( # MEMBER, &STRUCT::MEMBER, offsetof( STRUCT, MEMBER ) ) while(0)
// ^ name as str ^ ptr to memb ^ check against dynamic offset
I have one question: what do you get out of it ?
I mean it's a clever piece of code but:
you're fiddling with memory, the chances of blow-up are huge
it's quite complicated too, I didn't get everything and I would certainly have to pose longer...
What I am really wondering is what you actually want...
For example, using Boost.Fusion
struct a_key { typedef char type; };
struct object_key { typedef Foo type; };
typedef boost::fusion<
std::pair<a_key, a_key::type>,
std::pair<object_key, object_key::type>
> data_type;
int main(int argc, char* argv[])
{
data_type data;
boost::fusion::at_key<a_key>(data) = 'a'; // compile time checked
}
Using Boost.Fusion you get compile-time reflection as well as correct packing.
I don't really see the need for "runtime" selection here (using a value as key instead of a type) when you need to pass the right type to the assignment anyway (char vs Foo).
Finally, note that this can be automated, thanks to preprocessor programming:
DECLARE_ATTRIBUTES(
mData,
(char, a)
(char, b)
(char, c)
(int, i)
(Foo, object)
)
Not much wordy than a typical declaration, though a, b, etc... will be inner types rather than attributes names.
This has several advantages over your solution:
compile-time checking
perfect compliance with default generated constructors / copy constructors / etc...
much more compact representation
no runtime lookup of the "right" member

Determine array size in constructor initializer

In the code below I would like array to be defined as an array of size x when the Class constructor is called. How can I do that?
class Class
{
public:
int array[];
Class(int x) : ??? { }
}
You folks have so overcomplicated this. Of course you can do this in C++. It is fine for him to use a normal array for efficiency. A vector only makes sense if he doesn't know the final size of the array ahead of time, i.e., it needs to grow over time.
If you can know the array size one level higher in the chain, a templated class is the easiest, because there's no dynamic allocation and no chance of memory leaks:
template < int ARRAY_LEN > // you can even set to a default value here of C++'11
class MyClass
{
int array[ARRAY_LEN]; // Don't need to alloc or dealloc in structure! Works like you imagine!
}
// Then you set the length of each object where you declare the object, e.g.
MyClass<1024> instance; // But only works for constant values, i.e. known to compiler
If you can't know the length at the place you declare the object, or if you want to reuse the same object with different lengths, or you must accept an unknown length, then you need to allocate it in your constructor and free it in your destructor... (and in theory always check to make sure it worked...)
class MyClass
{
int *array;
MyClass(int len) { array = calloc(sizeof(int), len); assert(array); }
~MyClass() { free(array); array = NULL; } // DON'T FORGET TO FREE UP SPACE!
}
You can't initialize the size of an array with a non-const dimension that can't be calculated at compile time (at least not in current C++ standard, AFAIK).
I recommend using std::vector<int> instead of array. It provides array like syntax for most of the operations.
Use the new operator:
class Class
{
int* array;
Class(int x) : array(new int[x]) {};
};
I don't think it can be done. At least not the way you want. You can't create a statically sized array (array[]) when the size comes from dynamic information (x).
You'll need to either store a pointer-to-int, and the size, and overload the copy constructor, assignment operator, and destructor to handle it, or use std::vector.
class Class
{
::std::vector<int> array;
Class(int x) : array(x) { }
};
Sorry for necroing this old thread.
There is actually a way to find out the size of the array compile-time. It goes something like this:
#include <cstdlib>
template<typename T>
class Class
{
T* _Buffer;
public:
template<size_t SIZE>
Class(T (&static_array)[SIZE])
{
_Buffer = (T*)malloc(sizeof(T) * SIZE);
memcpy(_Buffer, static_array, sizeof(T) * SIZE);
}
~Class()
{
if(_Buffer)
{
free(_Buffer);
_Buffer = NULL;
}
}
};
int main()
{
int int_array[32];
Class<int> c = Class<int>(int_array);
return 0;
}
Alternatively, if you hate to malloc / new, then you can create a size templated class instead. Though, I wouldn't really recommend it and the syntax is quite ugly.
#include <cstdio>
template<typename T, size_t SIZE>
class Class
{
private:
T _Array[sz];
public:
Class(T (&static_array)[SIZE])
{
memcpy(_Array, static_array, sizeof(T) * SIZE);
}
};
int main()
{
char int_array[32];
Class<char, sizeof(int_array)> c = Class<char, sizeof(int_array)>(int_array);
return 0;
}
Anyways, I hope this was helpful :)
I had the same problem and I solved it this way
class example
{
int *array;
example (int size)
{
array = new int[size];
}
}
Don't you understand there is not need to use vector, if one wants to use arrays it's a matter of efficiency, e.g. less space, no copy time (in such case if handled properly there is not even need to delete the array within a destructor), etc. wichever reasons one has.
the correct answer is: (quoted)
class Class
{
int* array;
Class(int x) : array(new int[x]) {};
};
Do not try to force one to use non optimal alternatives or you'll be confusing unexperienced programmers
Instead of using a raw array, why not use a vector instead.
class SomeType {
vector<int> v;
SomeType(size_t x): v(x) {}
};
Using a vector will give you automatic leak protection in the face of an exception and many other benefits over a raw array.
Like already suggested, vector is a good choice for most cases.
Alternatively, if dynamic memory allocation is to be avoided and the maximum size is known at compile time, a custom allocator can be used together with std::vector or a library like the embedded template library can be used.
See here: https://www.etlcpp.com/home.html
Example class:
#include <etl/vector.h>
class TestDummyClass {
public:
TestDummyClass(size_t vectorSize) {
if(vectorSize < MAX_SIZE) {
testVector.resize(vectorSize);
}
}
private:
static constexpr uint8_t MAX_SIZE = 20;
etl::vector<int, MAX_SIZE> testVector;
uint8_t dummyMember = 0;
};
You can't do it in C++ - use a std::vector instead:
#include <vector>
struct A {
std::vector <int> vec;
A( int size ) : vec( size ) {
}
};
Declare your array as a pointer. You can initialize it in the initializer list later through through new.
Better to use vector for unknown size.
You might want to look at this question as well on variable length arrays.