Implement copy-on-write idiom in MyVector - c++

I have my class which stores a collection of objects with their names
template <typename T>
class MyVector
{
private:
vector<T> objects;
vector<string> m_names;
size_t m_ref_ptr;
public:
MyVector()
{
m_ref_ptr = 1;
}
MyVector(const MyVector& other) : objects(other.objects),
m_ref_ptr(other.m_ref_ptr),
m_names(other.m_names)
{
m_ref_ptr++;
}
void push_back(const T& obj, const std::string& name)
{
copy_names();
objects.push_back(obj);
m_names.push_back(name);
}
void copy_names()
{
if (m_ref_ptr == 1)
{
return;
}
size_t temp_ref_ptr = 1;
vector<string> temp_names(m_names);
m_ref_ptr--;
m_ref_ptr = temp_ref_ptr;
m_names = temp_names;
}
The task is to use copy-on-write idiom for names for efficiency.
I tried something, but I am not sure why do we need this, if everything works okay in my class without this copy-on-write, I read about this idiom: the main idea is: we create real copy when we want to write something, with purpose to write.
My code is really simple. Please, give me a tipe how to do this in my code?

Sorry, can not add to the comments because I don't have enough reputation points yet, so I write this as answer:
Given m_names is a std::shared_ptr, in copy_names (and assuming using namespace std you write:
if (m_names.use_count() > 1) { // this is c++11
m_names = make_shared<vector<string>>(*m_names);
}
You can drop the m_ref_ptr member, because std::shared_ptr will keep track of this. In the constructor will have to create an empty vector:
MyVector()
{
m_names = make_shared<vector<string>>());
}
BTW, in your code the m_ref_ptr was not changing the reference count in the original object, i.e. if you would have done:
MyVector a;
...
MyVector b = a;
then you would still have a.m_ref_ptr == 1. std::shared_ptr takes properly care of this.

Related

How can I express returning either a vector or a reference to an allocated vector?

I have a function that should return either a new vector or a reference to an existing one. I need this because in some situations the vector is already created and owned by somebody else and I want to avoid copying it.
One option is to return std::variant<std::vector<int>, std::vector<int>&>, but then the caller needs to add logic to discern what was returned. (NOT ALLOWED)
Another option is to use a wrapper class (I avoid templates for clarity):
class VectorContainer {
VectorContainer() : v(std::vector<int>()), v_ptr(nullptr) {}
VectorContainer(std::vector<int>& ref): v_ptr(&ref) {}
std::vector<int>& get() {
if (v_ptr == nullptr) return v;
return *v_ptr;
}
private:
std::vector<int> v;
std::vector<int>* v_ptr;
};
VectorContainer f();
The reference is guaranteed to outlive VectorContainer and additionally, the code that owns the vector is fixed and you cannot change it. I believe this disallows using something like a shared pointer.
Is there an existing class in the standard library? If not, how can I do this?
Your approach is close, but I would suggest having the reference always refer to the proper object:
class VectorContainer {
private:
std::vector<int> v_own;
public:
std::vector<int>& data;
VectorContainer(std::vector<int> own) : v_own{std::move(own)}, data{v_own} {}
VectorContainer(std::vector<int>& ref) : v_own{}, data{ref} {}
~VectorContainer() = default;
VectorContainer& operator=(VectorContainer const&) = delete;
VectorContainer& operator=(VectorContainer&&) = delete;
VectorContainer(VectorContainer const& from) :
v_own{from.v_own},
data{(&from.v_own == &from.data)?v_own:from.data} {
}
VectorContainer(VectorContainer&& from) :
v_own{std::move(from.v_own)},
data{(&from.v_own == &from.data)?v_own:from.data} {
}
};
Here you always access data or you could hide data and add a wrapper like this:
std::vector<int>& operator*() const {
return data;
}
// or a conversion operator to std::vector<int>&
Either way, whether or not there is indirection is hidden from the user. You always see a reference. Note that lugging around an empty vector has virtually no overhead. The initialisation is minimal.
Example:
struct Example {
std::vector<int> v{1,2,3};
VectorContainer example(bool const b) {
if (b)
return VectorContainer(std::vector{0}); // new vector
else
return VectorContainer(v); // reference to v
}
};

The element without default constructor in the custom template container

I need to create a simple template container, which can store any object of any type and could be used everywhere. So, I did something like this:
template <typename Type>
class Container {
public:
Container() : arraySize(10) { valueWrappers = new Type[arraySize];}
Container(const Container& other) { /* --- */}
~Container() { /* --- */}
Container& operator=(const Container& other) { /* --- */}
/* some functions */
private:
int arraySize;
Type* valueWrappers;
};
Now I have the problem - when I'm trying to create my container using as template a class without default constructor, the compilation error appears:
class MyClass {
public:
MyClass(int value) :v(value) { }
private:
int v;
};
int main() {
Container<MyClass> cont;
return 0;
}
C2512 'MyClass': no appropriate default constructor available
The problem is that I need to initialize the array of "Type" values with something, but I don't no what I need to use. I can't use NULL because, in this case, Container will work only with pointers. So, can somebody give an advice, how am I able to do it? Or, maybe, there is another way to solve this task?
Based on your requirements, I think you're going to have to use placement new. Since you haven't provided all the relevant code, I'm going to do what I can.
First, you're going to have to allocate raw memory instead of using new directly.
Container() : arraySize(10) { valueWrappers = reinterpret_cast<Type*>(::operator new(sizeof(Type) * arraySize)); }
Now when you put something in your Container, you'll have to construct it in place, using something like the following:
new (valueWrappers + index) Type(arguments to type);
In your destructor, you'll need to explicitly call the destructors on any object that you used placement new for.
valueWrappers[index]->~Type();
Lastly, release the memory using ::operator delete.
::operator delete(valueWrappers);
Please bear in mind that this is a very quick and dirty answer, and this code can be hard to debug and maintain. You're going to have to keep track of what indexes in valueWrapper have been initialized and which haven't during cleanup. If possible, I highly recommend using something akin to std::vector, which handles all this complexity for you.
One option is to not allocate the array in the default constructor, but initialise valueWrappers to null instead. Another option is to not have a default constructor in your template. Third option is to keep your class as-is and simply document that the template is default constructible only if the type argument is default constructible.
You can use std::optional to defer initialization, which is guaranteed to handle object lifetime correctly. Letting a default constructed container have 10 elements is also a questionable choice — a (count) constructor may be preferable.
template <typename Type>
class Container {
using elem_t = std::optional<Type>;
std::size_t count{};
std::unique_ptr<elem_t[]> elems{};
public:
Container() = default;
Container(std::size_t cnt)
: count{cnt}
, elems{std::make_unique<elem_t[]>(cnt)}
{
}
// for example
template <typename... Args>
void construct_at(std::size_t pos, Args&&... args)
{
assert(pos < count);
assert(!elems[pos]);
elems[pos].emplace(std::forward<Args>(args)...);
}
// ...
};
Note that I used std::unique_ptr to simplify memory management; a pointer will also be OK, though apparently more error-prone. Now you can traverse the container and construct the elements:
class MyClass {
public:
MyClass(int value) :v(value) { }
private:
int v;
};
int main()
{
Container<MyClass> cont(10);
for (std::size_t i = 0; i < 10; ++i) {
cont.construct_at(i, /* argument */);
}
}

How to implement a method that calls any constructor like emplace_back in vector? [duplicate]

I need to implement a container to hold an amount of elements and for some reason, it has to work without any heap allocation. Another requirement is, that the container elements should not be copied or moved in any way. They have to constructed directly into the memory allocated by the container.
For that, I decided to use placement new and delegate the memory management completely to the container implementation (found some useful information about placement new at drdobbs).
A running example is found here.
(Please note, that the use of new uint8_t[size] and std::queue is just to keep the example simple. My real code has more complex, heap-less implementation instead.)
This perfectly works so far, as the client code has to put elements into the container with calls like:
executer.push(new (executer) MyRunnable("Hello", 123));
Now I want do remove the need of the repeated write executer in this statement. I would rather like to write something like e.g.:
executer.pushNew(MyRunnable("Hello", 123));
or
executer.pushNew(MyRunnable, "Hello", 123);
maybe by providing an appropriate template but I failed to write one (no preprocessor macros, please).
I'd found some useful information about std::allocator here at drdobbs but don't know how to apply it to my problem (further, the article is of anno 2000 and so don't take use of possible C++11 advantages).
Could one help me to find a way to not longer need to give the executer twice?
Edit: After successful approving Jarod42's answer, I'd updated my running example code here.
And for the history, here the original example code of my initial question:
#include <iostream>
#include <queue>
class Runnable {
// Runnable should be uncopyable and also unmovable
Runnable(const Runnable&) = delete;
Runnable& operator = (const Runnable&) = delete;
Runnable(const Runnable&&) = delete;
Runnable& operator = (const Runnable&&) = delete;
public:
explicit Runnable() {}
virtual ~Runnable() {}
virtual void run() = 0;
};
class MyRunnable: public Runnable {
public:
explicit MyRunnable(const char* name, int num): name(name), num(num) {}
virtual void run() override {
std::cout << name << " " << num << std::endl;
}
private:
const char* name;
int num;
};
class Executer {
// Executer should be uncopyable and also unmovable
Executer(const Executer&) = delete;
Executer& operator = (const Executer&) = delete;
Executer(const Executer&&) = delete;
Executer& operator = (const Executer&&) = delete;
public:
explicit Executer() {
}
void* allocateEntry(size_t size) {
// this heap allocation is just to keep this example simple
// my real implementation uses it's own memory management instead (blockpool)
return new uint8_t[size];
}
void push(Runnable* entry) {
queue.push(entry);
}
template <typename R> // this don't works
void pushNew(R) {
push(new (*this) R);
}
inline friend void* operator new(size_t n, Executer& executer) {
return executer.allocateEntry(n);
}
void execute() {
while (queue.size() > 0) {
Runnable* entry = queue.front();
queue.pop();
entry->run();
// Now doing "placement delete"
entry->~Runnable();
uint8_t* p = reinterpret_cast<uint8_t*>(entry);
delete[] p;
}
}
private:
// this use of std::queue is just to keep this example simple
// my real implementation uses it's own heap-less queue instead
std::queue<Runnable*> queue {};
};
int main() {
Executer executer;
executer.push(new (executer) MyRunnable("First", 1));
executer.push(new (executer) MyRunnable("Second", 2));
executer.push(new (executer) MyRunnable("Third", 3));
// but want to use it more like one this
//executer.pushNew(MyRunnable("Fifth", 5)); // how to implement it?
//executer.pushNew(MyRunnable, "Sixth", 6); // or maybe for this usage?
executer.execute();
}
There are two things wrong with this:
template <typename R> // this don't works
void pushNew(R) {
push(new (*this) R);
}
The first is answered by Jarod42 in that you want to do:
template <typename R, typename... Ts>
void pushNew(Ts&&... args) {
push(new (*this) R(std::forward<Ts>(args)...));
}
but even more importantly... new (*this) R is really bizarre. It looks like you're constructing an R over yourself! But you're not, you're just using that syntax to call your allocator. That horribly violates the principle of least surprise. It took me quite a while to understand what was going on.
What you should to is just use your allocator directly:
template <typename R, typename... Ts>
void pushNew(Ts&&... args) {
void* slot = allocateEntry(sizeof(R));
push(new (slot) R(std::forward<Ts>(args)...));
}
That is a lot easier to understand.
With:
template <typename R, typename... Ts>
void pushNew(Ts&&... args) {
push(new (*this) R(std::forward<Ts>(args)...));
}
You can write:
executor.PushNew<MyRunnable>("Hello", 123);
instead of
executer.push(new (executer) MyRunnable("Hello", 123));

How to pass data to a templated collection

I have to write a generic data structure that resembles a C++ vector as part of an assignment.
This is my idea for the Vector:
template<typename T>
class MyVector {
private:
T* data_;
size_t size_;
public:
MyVector();
MyVector(const MyVector &otherVector);
// which one should I use?
add(const T& value);
add(T value);
~MyVector();
};
Now I wonder how to pass values to the methods. Coming from Java I am a bit overwhelmed. In Java you wouldn't hesitate and pass the value by reference, the GC would never delete the object if it is still referenced.
In C++ you would create a mess if you would pass by reference considering code like this:
void myFunction(MyVector &myVector) {
int a = 5;
myVector.add(a);
}
int main() {
auto vector = MyVector<int>();
myFunction(vector);
// now the vector contains a reference to
// something that doesn't exist anymore.
}
How do you solve this problem? Would you just pass by reference and create a copy or do you pass by value (which creates a copy for you)
Looking at the C++ std::vector interface I see that they use references.
I just don't see the value of passing by reference if you have to create your own copy.
add(const T& value) is ok, you just should be sure that there is properly defined assign operator for T. So, the implementation will be:
void Add(const T& value) {
if (m_size == m_maxSize) realloc(); // stuff to have enough space
m_data[m_size++] = value; // here copy is creating
}
default impl of assign operator just byte-copy fields of class, it is not always correct.
Other solution, if you want more java-style semantic, is to make T = shared_ptr<YourType> or T = YourType*
The latter is rather difficult because require skill of manual lifetime control, so is undesirable for c++ beginners.
void myFunction(MyVector<shared_ptr<X>> & myVector)
{
shared_ptr<X> x(new X(...));
myVector.add(x);
}
works similar to references in Java.
Other way, that was used in old times:
template<typename T>
class MyVector {
private:
T** data_; // now you have array of pointers, so should be careful
....
add(T* value);
....
}
void myFunction(MyVector<X> & myVector)
{
X * x = new X(...);
myVector.add(x); // now x belongs to myVector and it should handle its lifetime
}

Recombinate two complex attributes into new object

I want to recombine a (complex) member attribute of two agents and put it in a new agent. It's a vector of numbers, every second value is taken from agent1, the rest from agent2. The problem is, I want to be able to exchange the implementation of my numberList, maybe another numberListInt2 using integers or like in my example using floats:
#include <vector>
using namespace std;
class NumberList {
};
class NumberListInt : public NumberList {
vector<int> number_list {1,2,3};
};
class NumberListFloat : public NumberList {
vector<float> number_list {1.2f,2.5f,30.0f};
};
class Agent {
NumberList* numbers;
public:
Agent();
Agent(NumberList* numbers) {
numbers = numberList*
}
~Agent() {
delete numbers;
}
NumberList* recombine(Agent& other) {
NumberList* new_number_list;
if(true) // a boolean config value
new_number_list = new NumberListInt();
else
new_number_list = new NumberListFloat();
for(unsigned int i=0;i<3;i++) {
if(i%2)
new_number_list[i] = other.get_number_list()[i];
else
new_number_list[i] = numbers[i];
}
return new_number_list;
}
NumberList* get_number_list() {
return numbers;
}
};
int main ()
{
Agent agent;
Agent agent2;
Agent agent3(agent.recombine(agent2));
return 0;
}
My questions:
How to implement the operator [] of NumberList?
Is there a better way than using a pointer for the polymorphism?
Do I free the memory correctly?
Thanks in advice!
The problem is that operator[] shall return a reference to an item of the NumberList. But you don't know the type of the numbers, when you're in the parent class. So you won't be able to define this operator in a polymorphic manner (unless you define somehow a polymorphic item).
To benefit from polymorphism you have to use references or pointers. In your case the pointers are a good alternative. However you have to clarify their use in the constructors. I assume that the copy constructor should copy the object and not reuse the list of the original agent.
No, because you have not defined a virtual destructor for NumberList. And when you recombine() you return a newly allocated list. So the caller has to delete the returned object. That's very dangerous: if he forget, memory will leak. You'd better consider opting for shared_ptr to avoid leaking.
It's not clear if you need dynamic change of the NumberList type at runtime. If you don't, a safer approach would be to use templates
With templates it would look like:
template <class T>
class NumberList {
vector<T> number_list;
T& operator[] (size_t i) { return numberlist[i]; } // may be add boundary check ?
};
template <class T>
class Agent {
NumberList<T> numbers; // No more pointer, but directly the object
....
};