Access a member of all structs in an array - c++

I have a struct Foo;
typedef struct {
int bar;
char baz;
} Foo;
Suppose I then declare an array of Foo as;
Foo* arr = new Foo[300];
And proceed to initialize every member with a loop. I would like very much to be able to get an array of all members bar;
int* barr_arr = ...
What is the most efficient way to do this? Is there some way to exploit the memory layout such that I need not loop over the entire Foo array?
Since we know the memory layout in advance could we exploit the fact that we know the address of every member if we're clever about alignment?

What is the most efficient way to do this? Is there some way to exploit the memory layout such that I need not loop over the entire Foo array?
I don't think there is away to do that without looping. You can simplify your code by using std::transform but std::transform does loop.
Also, I would recommend using std::vector instead of allocating an array using new.
std::vector<Foo> arr(300);
....
std::vector<int> bArr(arr.size());
std::transform(arr.begin(), arr.end(), bArr.begin(), [] -> (Foo const& f) { return f.bar; });

When you are initializing the first array, you can grab a pointer to the field inside each element and store that in a separate array.
struct Foo
{
int bar;
float baz;
};
const int SIZE = 5;
Foo foos[SIZE];
int *bars[SIZE];
for(int c = 0; c < SIZE; c++) {
foos[c].bar = c;
foos[c].baz = c;
bars[c] = &foos[c].bar; // Grab pointer to field
}
for(int c = 0; c < SIZE; c++) {
std::cout << "Bar Value: " << *bars[c] << std::endl;
}

If Foos typically exist in arrays, and corresponding arrays of bars and bazs often need to be accessed, I would suggest redesigning your data structures to better suit your problem. Obviously, we're not reading the code that inspired this question, but given the information provided, I might suggest something like:
struct FooArray {
int* bars;
char* bazes;
size_t n_elements;
};
This removes the need to allocate a new buffer for the bar array, which, depending on how many Foos are being processed, might entail significant memory savings.
I would also note that, if you're not working at a low level and don't actually need an int* but can do with a std::vector<int>, then #R Sahu's answer is likely a more appropriate solution.

The goal drives the design.
If your main use is to pass all bar members in a row, same for baz members, then create separate containers:
std::vector<int> bar;
std::vector<char> baz;
Then passing bar as an array is straightforward: just use bar.data().

If you add a constructor to your Foo that takes the size of array, you could have only one object of Foo. You can then make it that you can access either the whole vector data or individual elements with subscript:
#include <iostream>
#include <vector>
#include <memory>
struct Foo
{
std::vector<int> bars;
std::vector<char> bazs;
std::size_t size;
Foo(size_t size, int bar = 0, char baz = 0) :
bars(size, bar), bazs(size, baz), size{size}
{
}
auto operator[](size_t n)
{
// if (n >= size) ...
struct
{
int &bar;
char &baz;
} temp{ bars[n], bazs[n] };
return temp;
}
};
int main()
{
Foo arr(30, 100, 'a'); // 30 items
std::cout << arr[29].bar << std::endl;
std::cout << arr[29].baz << std::endl;
std::cout << arr.bars[29] << std::endl;
std::cout << arr.bazs[29] << std::endl;
std::unique_ptr<Foo> arr2 = std::make_unique<Foo>(25, 10, 'b'); // 25 items
std::cout << arr2->operator[](15).bar << std::endl;
std::cout << arr2->operator[](15).baz << std::endl;
arr2->bars[15] = 11;
std::cout << arr2->bars[15] << std::endl;
arr2->bazs[15] = 'c';
std::cout << arr2->bazs[15] << std::endl;
return 0;
}
Demo: https://ideone.com/TiVwOT
100
a
100
a
10
b
11
c

Related

Array of objects without default constructors on the stack?

I can achieve the functionality I need using option 3, however I would like to investigate whether it is possible to create the array on the stack instead.
#include <array>
#include <vector>
struct NotDefaultConstructable
{
NotDefaultConstructable(int val){};
};
int main()
{
//std::array<NotDefaultConstructable, 5> aA; // Fails to compile. [On stack]
//std::vector<NotDefaultConstructable> aV(5); // Fails to compile. [On heap]
std::vector<NotDefaultConstructable> aV; // Compiles. [ On heap]
aV.reserve(5);
}
std::array is an aggregate class type which may have a trivial, implicitly defaulted constructor. If T is not default-constructible, the implicit default constructor is defined as deleted, as per [class.ctor]/5.3.
As this applies in your case, you cannot construct an object of std::array<NotDefaultConstructable, 5> by default construction. You can, however, construct it by means of aggregate initialization:
#include <array>
struct NotDefaultConstructable {
NotDefaultConstructable(int){};
};
int main() {
std::array<NotDefaultConstructable, 3> arr{1, 2, 3};
}
In this sense, all elements of a std::array object should arguably be initialized, even if they represent a non-present object (yet to be "filled", if you will).
You could either find a an appropriate static vector container, such as boost::static_vector, or you could e.g. implement a thin wrapper around std::array which stores an array as above as well its runtime size. Another alternative would be to use a std::array of optionals:
#include <array>
#include <iostream>
#include <optional>
struct NotDefaultConstructable {
NotDefaultConstructable(int val) : val_(val) {};
int val_;
};
int main() {
std::array<std::optional<NotDefaultConstructable>, 3> arr{};
arr[1] = NotDefaultConstructable{42};
for(const auto& element : arr) {
if(element.has_value()) {
std::cout << "has value: " << element.value().val_;
} // has value: 42
}
}
where no dynamic memory allocation takes place (cppreference):
If an optional contains a value, the value is guaranteed to be allocated as part of the optional object footprint, i.e. no dynamic memory allocation ever takes place.
Judging by the fact that OP mentioned looking into using placement new, I wanted to make a full example of using a stack allocated array as memory for dynamically constructed objects.
Using this method, you can allocate stack memory without initializing it with instances. The problem, however, is that you have to monitor the object lifetime for each instance yourself. In this example, I construct all of them and can then simply assume that all of them have to be destroyed, however monitoring how many instances are alive and should be destroyed is quite messy.
This is why dfrib's answer is much more suitable in your situation, as it allows you to allocate the memory on the stack using std::array<std::optional<Type>, 5> and assign instances later. Object lifetime will also be managed for you, so is much more advisable.
Example 1: Placement New:
#include <array>
#include <iostream>
struct NotDefaultConstructable {
int Value;
NotDefaultConstructable(int val) : Value(val) {
std::cout << "constructed: " << Value << "\n";
};
~NotDefaultConstructable(){
std::cout << "destructed: " << Value << "\n";
}
};
int main() {
// allocate enough memory on the stack for 5 instances
char aV[sizeof(NotDefaultConstructable) * 5];
// get a pointer to the first NotDefaultConstructable in that array
auto avArray = static_cast<NotDefaultConstructable*>(static_cast<void*>(&aV[0]));
// use placement new to construct each instance
for (auto i = 0; i < 5; ++i)
new (&avArray[i]) NotDefaultConstructable((i + 1) * 2);
// do stuff with the instances
for (auto i = 0; i < 5; ++i)
std::cout << "instance: " << avArray[i].Value << "\n";
// destruct them all manually, this is what makes placement new a little
// cumbersome. I would advise to use std::optional instead.
for (auto i = 0; i < 5; ++i)
avArray[i].~NotDefaultConstructable();
}
example 1: https://godbolt.org/z/7jW8Pb
Example 2: std::array with std::optional
Here's an example using std::optional, which has minor overhead (about ~4 bytes per object) to achieve much more convenience:
#include <array>
#include <optional>
#include <iostream>
struct NotDefaultConstructable {
int Value;
NotDefaultConstructable(int val) : Value(val) {
std::cout << "constructed: " << Value << "\n";
};
~NotDefaultConstructable(){
std::cout << "destructed: " << Value << "\n";
}
};
int main() {
// allocate enough memory on the stack for 5 instances
std::array<std::optional<NotDefaultConstructable>, 5> avArray;
// use placement new to construct each instance
for (auto i = 0; i < 5; ++i)
avArray[i] = NotDefaultConstructable((i + 1) * 2);
// do stuff with the instances
for (auto i = 0; i < 5; ++i)
std::cout << "instance: " << avArray[i].value().Value << "\n";
}
example 2: https://godbolt.org/z/Ynx8aE
You can try the following
#include <iostream>
struct NotDefaultConstructable {
NotDefaultConstructable(int val) {
};
};
int main() {
NotDefaultConstructable aV[5] { 6, 6, 6, 6, 6 };
}

std::vector with elements allocated on the heap - do I need rule of 5?

If I have a class with members like this:
class MyClass {
public:
void set_my_vector() {
for (int ind = 0; ind < 3; ++ind) {
my_vector.push_back(new MyStruct(i, i*2));
}
}
private:
struct MyStruct {
int num_a;
int num_b;
MyStruct(int i, int j) : num_a(i), num_b(j) {}
};
std::vector<MyStruct*> my_vector;
};
Do I need to write the rule-of-five functions, or will std::vector take care of deep copying and deleting the elements allocated on the heap?
EDIT:
The following code uses default copy constructor, so I assume that after I copy my_class1 object into my_class2 object, the elements of my_class1.my_vector and my_class2.my_vector will be the same, because the MyStruct pointers were copied, but not the data itself. However, the output shows that they are not the same. You can run the code here: https://onlinegdb.com/S1pK9YE4v
#include <iostream>
#include <vector>
class MyClass {
public:
void fill_my_vector(int i, int j) {
my_vector.clear();
for (int ind = 0; ind < 3; ++ind) {
my_vector.push_back(new MyStruct(i, j));
}
}
void print () {
for (int ind = 0; ind < 3; ++ind) {
std::cout << my_vector[ind]->int1 << ", " << my_vector[ind]->int2 << std::endl;
}
std::cout << std::endl;
}
private:
struct MyStruct {
MyStruct (int i, int j) :
int1(i), int2(j)
{}
int int1;
int int2;
};
std::vector<MyStruct*> my_vector;
};
int main()
{
MyClass my_class1;
my_class1.fill_my_vector(42, 43);
std::cout << "my_class1: " << std::endl;
my_class1.print();
MyClass my_class2 = my_class1;
my_class2.fill_my_vector(12, 13);
std::cout << "my_class2: " << std::endl;
my_class2.print();
std::cout << "my_class1: " << std::endl;
my_class1.print();
}
EDIT2: I know about smart pointers. I am specifically interested what happens if I use raw pointers.
You need to implement the copy constructor, copy assignment and destructor.
Additionally, consider changing your vector declaration from
std::vector<MyStruct*> my_vector;
to
std::vector<std::unique_ptr<MyStruct>> my_vector;
so that it actually owns the heap allocated objects properly. Doing this change will help you not write a destructor.
No, std::vector doesn't take care of deep copying of your objects stored by pointer. You have few possibilities to solve this:
Store MyStruct by value.
Store std::unique_ptr<MyStruct>.
Store std::shared_ptr<MyStruct>.
Note that because MyStruct contains only fields of the primitive types, neither of copy constructor, assignment operator and destructor are needed, otherwise you'd have to implement them, default implementation which compiler will generate automatically will be good enough.

Use-case and behavior of `this[i]`

I want to know what is the use scope of this[i]. I know this is clearly an useless question but let say it for science. What are the behaviors allow by the standard for indexing this ? I didn't find information about it, cppreference.
Stupid example:
#include <iostream>
class foo {
public:
int value;
void bar(std::size_t size, int a) {
for (std::size_t i = 0; i < size; i++) {
this[i].value = a--;
}
}
};
int main() {
foo foos[42];
(*foos).bar(sizeof foos / sizeof *foos, 42);
for (auto &foo : foos) {
std::cout << foo.value << std::endl;
}
return 0;
}
Is it only allow with array ? Maybe. What about heritage ? I think it's undefined behavior. Do you know some use-case ? It's just some questions about this[i], don't answer to these directly if you don't want to.
this is just a pointer. The ptr[n] syntax is identical to *(ptr + n).
Do you know some use-case ?
No, there's no valid reason to use this[n]. The class itself shouldn't assume that the current instance is part of an array or that there are other instances close by in contiguous memory.
Design the class in such a way that it will work independently of where/how it is instantiated.
Your code can be modernized/improved significantly.
Use std::array instead of C-style arrays.
Don't do manual pointer arithmetic.
Have foo only deal with the current instance.
Do not use endl unless you want to flush the cout buffer. Use \n instead.
class foo {
public:
int value;
void bar(int a) {
this->value -= a;
}
};
int main() {
std::array<foo, 42> foos;
for (auto &foo : foos) {
foo.bar(1);
std::cout << foo.value << '\n';
}
return 0;
}

What is the best way to return reference to a constant sized array of pointers?

I have an array of pointers declared as a class member like this:
class Bar
{
private:
static constexpr int SIZE = 10;
Foo* m[SIZE];
}
In one of my class methods, I would like to return a pointer (or preferably, a reference) to this array. The array has a known size at compile time, but I am keeping track of how many items I have put in there (it is a buffer of stuff).
What is the best way to return a reference to this array in C++11 ?
Here are the things I have tried:
GetArray(Foo* &f[], unsigned &size) const
I like the syntax because it makes it clear that the reference value is an array of pointers, but this gives a compiler error: Declared as array of references of type Foo*
GetArray(Foo** &f, unsigned &size) const
{
f = m;
size = mSize;
}
Gives me: Error: assigning to Foo **' from incompatible type Foo *const[10]. Casting mFoo to (Foo**) alleviates the error, but IMHO, this is not elegant.
Nobody posted an answer using std::array yet, it is a very simple replacement:
class Bar
{
std::array<Foo *, 10> m;
public:
std::array<Foo *, 10> & getArray() { return m; }
std::array<Foo *, 10> const & getArray() const { return m; }
};
This seems to me a lot simpler than the hoops you have to jump through to use your C-style array version.
To avoid code duplication you could typedef std::array<Foo *, 10> FooArray; .
The technique of having both a const and a non-const implementation is a common pattern for accessor functions which return a reference or a pointer. (It's not required if your accessor returns by value, of course).
I would seek to use a std::array or a std::vector in most cases. If you are determined to use a raw array then you could go this way with it:
typedef int Foo;
typedef Foo* (&FooPtrArrayRef)[10]; // to make the syntax less hairy
class Bar
{
private:
Foo* m[10];
public:
// First way without using typedef
Foo* (&getArray())[10]
{
return m;
}
// Nicer looking way with a typedef
FooPtrArrayRef getArrayByRef()
{
return m;
}
};
int main()
{
Bar b;
Foo* (&array)[10] = b.getArray();
std::cout << (sizeof(array) / sizeof(Foo*)) << '\n';
// Alternative using "size deduction"
Foo* (&array2)[sizeof(b.getArray()) / sizeof(Foo*)] = b.getArray();
std::cout << (sizeof(array2) / sizeof(Foo*)) << '\n';
// MUCH nicer using the typedef
FooPtrArrayRef array3 = b.getArrayByRef();
std::cout << (sizeof(array3) / sizeof(Foo*)) << '\n';
}
The syntax is pretty obscure though.
The benefits of this is approach is that it retains the full type information of the array you are passing by reference. The obscure syntax is necessary to avoid the type collapsing to a Foo**. By retaining the full type of the array you retain the ability to know its size at compile time using the sizeof() operator.
here's another approach that returns the array reference and the current size as a tuple:
#include <tuple>
#include <functional>
#include <algorithm>
#include <iterator>
#include <iostream>
struct Foo {};
using FooBuffer = Foo*[10];
class Bar
{
public:
Bar()
: _m { nullptr }
{
_m[0] = new Foo;
_m[1] = new Foo;
_items = 2;
}
~Bar() {
for(auto fp : _m)
delete fp;
}
std::tuple<FooBuffer&, size_t> getInfo() {
return std::make_tuple(std::ref(_m), _items);
}
private:
Foo* _m[10];
size_t _items;
};
int main() {
Bar b;
auto info = b.getInfo();
FooBuffer& buf = std::get<0>(info);
size_t items = std::get<1>(info);
for(Foo** p = buf ; p != buf + items ; ++p) {
std::cout << "Foo at " << std::hex << *p << std::endl;
}
return 0;
}

C++ error when using struct variable

I have this struct:
struct noduri {
int nod[100];
};
and this function:
int clearMatrix(int var)
{
cout << all[1].nod[30];
}
int main()
{
noduri all[100];
cout << all[1].nod[30];
return 0;
}
and I want the struct to be assigned to all 100 elements of array all[], when I do cout << all[1].nod[30]; everything works fine, no errors, it outputs 0. When I call clearMatrix(1) I get this error : error: request for member nod in all[1], which is of non-class type int, what am I doing wrong ?!
The array variable all is local to the main function, so you cannot reference it in clearMatrix unless you pass a pointer to it into the function:
int clearMatrix(int var, noduri *all)
{
cout<<all[1].nod[30];
}
int main()
{
noduri all[100];
clearMatrix(5, all);
return 0;
}
you are reffering in the function that array which is not in its scope, you need to do it as
int clearMatrix(int var,noduri *all)
{
cout<<all[1].nod[30]; // as here you have the base address of the array of type noduri you can refer it.
}
int main()
{
noduri all[100];
clearMatrix(5, all);
return 0;
}
You are using raw arrays. That's not a good idea. Use std::vector if the size if not known at compile time, consider std::array if it is known at compile time and dynamic resizing would cause measurable performance problems.
One of the problems with raw arrays in C++ is that it's not at all(!) as easy to pass them to a function like, say, an int or a double. std::vector and std::array, in contrast, are as easy to pass to a function like any other normal type.
Here's a complete example:
#include <array>
#include <iostream>
struct noduri {
std::array<int, 100> nod;
};
void clearMatrix(std::array<noduri, 100> const &array) {
std::cout << array[1].nod[30];
}
int main() {
std::array<noduri, 100> all;
std::cout << all[1].nod[30];
}
Note that std::array is only available if your compiler supports C++11. For an older compiler, use boost::array or just do it with a std::vector.
The code you showed will not be compiled and has no any sense. If I have understood correctly you want to assign each element of the array by some value in function clearMatrix. If so then the code will look the following way
#include <iostream>
struct noduri
{
int nod[100];
};
int clearMatrix( noduri *matrix, int size, int var )
{
for ( int i = 0; i < size; i++ )
{
for ( int &n : matrix[i].nod ) n = var;
}
}
int main()
{
const int N = 100;
noduri all[N] = {};
std::cout << all[1].nod[30] << std::endl;
clearMatrix( all, N, 10 );
std::cout << all[1].nod[30] << std::endl;
return 0;
}