I needed a vector of a base class, and everywhere I looked the solution was to store it as a pointer. However, storing pointers makes things harder to use because of the lack of value semantics.
struct base
{
int a = 10;
};
struct derived : public base
{
int b = 5;
};
int main()
{
std::vector<std::reference_wrapper<base>> vec;
vec.push_back(*(new derived));
auto elem = static_cast<derived*>(&vec.at(0).get());
std::cout << elem->b << std::endl; // prints 5
return 0;
}
Is there any downside to just storing them as an std::reference_wrapper?
Related
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.
I would like to have a unique_ptr class member that points to the base class, but later in the constructor through polymorphism can be changed to point to a sister class that also derives from the same base class.
While I don't get any errors in the constructor setting this polymorphism, it does not seem to work correctly, since I get error messages that my polymorphic pointer can't find a member of the sister class to which I thought the pointer was now pointing.
How do I correctly achieve polymorphism here?
class A {
int bar;
};
class B : public A {
int foo;
};
class C: public A {
C();
std::unique_ptr<A> _ptr; // changing to std::unique_ptr<B> _ptr removes the "class A has no member 'foo'" error
};
C::C() : A()
{
_ptr = std::make_unique<B>(); // no errors here
int w = _ptr->foo; // class A has no member 'foo'
}
When you assign
_ptr = std::make_unique<B>();
This works because B is a derived class of A, however _ptr is still a unique_ptr to the base class. You can't change the type of a variable after it's declared.
So what are your options?
Because you know that _ptr stores a pointer to the derived class B, you can do a cast after dereferencing it:
_ptr = std::make_unique<B>();
// derefence the pointer, and cast the reference to `B&`.
B& reference_to_sister = (B&)(*_ptr);
int w = reference_to_sister.foo;
If you take this approach, you'll have to somehow keep track of which derived class is in _ptr, or you'll run the risk of running into bugs.
Alternatively, if you're using C++17, you can use std::variant:
class C : public A {
void initialize(A& a) {
// Do stuff if it's the base class
}
void initialize(B& b) {
// Do different stuff if it's derived
int w = b.foo;
}
C() {
_ptr = std::make_unique<B>(); // This works
// This takes the pointer, and calls 'initialize'
auto initialize_func = [&](auto& ptr) { initialize(*ptr); };
// This will call 'initialize(A&)' if it contains A,
// and it'll call 'initialize(B&)' if it contains B
std::visit(initialize_func, _ptr);
}
std::variant<std::unique_ptr<A>, std::unique_ptr<B>> _ptr;
};
In fact, if you use std::variant this will work even if A and B are completely unrelated classes.
Here's another short variant example
#include <variant>
#include <string>
#include <iostream>
void print(std::string& s) {
std::cout << "String: " << s << '\n';
}
void print(int i) {
std::cout << "Int: " << i << '\n';
}
void print_either(std::variant<std::string, int>& v) {
// This calls `print(std::string&) if v contained a string
// And it calls `print(int)` if v contained an int
std::visit([](auto& val) { print(val); }, v);
}
int main() {
// v is empty right now
std::variant<std::string, int> v;
// Put a string in v:
v = std::string("Hello, world");
print_either(v); //Prints "String: Hello, world"
// Put an int in v:
v = 13;
print_either(v); //Prints "Int: 13"
}
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
In C++, I have a class MyClass, which during construction takes a reference to an int to create an internal reference to it.
I then have a class BigClass, containing both an std::vector<int> vecInt_ and an std::vector<MyClass> vecMyClass_. The constructor of BigClass takes as an argument the size of the vectors vecInt_ and vecMyClass_. In the constructor of BigClass, I would like to have each element of vecMyClass_ use in its constructor the corresponding element of vecInt_.
How could I write that ? If I could call the constructors of vecMyClass from the body of the constructor of BigClass, that would look like that :
BigClass(int nbElem) :
vecInt_(nbElem),
vecMyClass_(nbElem)
{
for (int i = 0; i < nbElem; ++i)
{
vecMyClass_[i](vecMyInt_[i]);
}
}
But of course the parenthesis here would mean operator(), and not the constructor. I cannot write something like:
vecMyClass_[i] = MyClass(vecMyInt_[i]);
Because MyClass contains a reference and not a pointer, and thus referenced value can not be modified.
You could initialize vecMyClass_ as an empty vector and emplace_back elements into it while you construct them:
BigClass(int nbElem) :
vecInt_(nbElem),
vecMyClass_() //empty vector
{
vecMyClass_.reserve(nbElem); //avoid reallocations
for (int i = 0; i < nbElem; ++i)
{
vecMyClass_.emplace_back(vecInt_[i]);
}
}
It doesn't sound like a very good idea. At some point adding elements to vecMyInt_ will result in expanding the vector, i.e. allocating new memory and moving the elements there, and freeing the old memory. This means that the references kept by instances of MyClass will be invalid.
Of course this won't be a problem if you reserve the capacity beforehand, and never add elements to the vector.
#include <vector>
#include <iostream>
struct MyClass {
int& x;
MyClass(int& x) : x(x) {}
};
struct BigClass {
BigClass(std::size_t nb_elems) : ints(nb_elems) {
my_classes.reserve(nb_elems);
for(int& x : ints) {
my_classes.emplace_back(x);
}
}
std::vector<int> ints;
std::vector<MyClass> my_classes;
};
int main()
{
BigClass b{10};
for(int& x : b.ints) {
x = 23;
}
// they are all 23
for(auto& c : b.my_classes) {
std::cout << c.x << std::endl;
// change them
c.x = 24;
}
// they are all 24 now
for(auto& c : b.ints) {
std::cout << c << std::endl;
}
return 0;
}
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;
}