Make a safe Reader/Writer vector - c++

Inspired by this code, I am trying to implement a Reader/Writer vector that can safely call push_back() concurrently by threads.
Once this class is in place, I might then create method erase() by calling std::swap(), which swaps the target item and the last item and then erase the last item in the collection. In this way, I assume that the performance should be fair because deleting an item in the middle of collection does not invoke moving all items following the target item in the collection.
Unfortunately, the following code:
#include <vector>
#include <boost/thread/shared_mutex.hpp> //shared_mutex
#include <memory> //shared_ptr
#include <utility> //swap()
template <class T>
class readers_writer_vector
{
std::shared_ptr<boost::shared_mutex> pm;
std::vector<T> data;
public:
readers_writer_vector() :
pm(new std::shared_ptr<boost::shared_mutex>){}
void push_back(const T& item){
boost::unique_lock<boost::shared_mutex> lock(*pm); //wrong design
data.push_back(item);
}
};
int main()
{
readers_writer_vector<int> db;
db.push_back(1);
return 0;
}
yields the following compilation errors:
/usr/include/c++/4.9/bits/shared_ptr_base.h:871:39: error: cannot convert ‘std::shared_ptr<boost::shared_mutex>*’ to ‘boost::shared_mutex*’ in initialization
: _M_ptr(__p), _M_refcount(__p)
// g++ -std=c++11 -Iboost -lboost t.cpp
How do I fix it? Please!
EDIT:
The implementation task is far more complicated than I thought. It didn't take too long before I encountered the problem #Danh had warned. Now I get these errors:
t.cpp:28:8: note: ‘i::i(const i&)’ is implicitly deleted because the default definition would be ill-formed:
struct i {
^
t.cpp:28:8: error: use of deleted function ‘readers_writer_vector<T>::readers_writer_vector(const readers_writer_vector<T>&) [with T = z]’
t.cpp:13:2: note: declared here
readers_writer_vector(readers_writer_vector const&) = delete;
with this version:
template <class T>
class readers_writer_vector
{
booster::shared_mutex m;
std::vector<T> data;
public:
readers_writer_vector() = default;
readers_writer_vector(readers_writer_vector const&) = delete;
void push_back(const T& item){
booster::unique_lock<booster::shared_mutex> lock(m);
data.push_back(item);
}
typename std::vector<T>::reference back(){
return data.back();
}
};
struct z {
int zipcode;
std::string address;
};
struct i {
int id;
readers_writer_vector<z> zipcodes;
};
int main()
{
readers_writer_vector<i> db;
db.push_back(i());
auto &ii=db.back();
ii.id=1;
ii.zipcodes.push_back(z());
auto &zz=ii.zipcodes.back();
zz.zipcode=11;
zz.address="aa";
return 0;
}
In addition to fixing the existing errors, I will have to implement iterators for readers_writer_vector to make this class useful.
I am pondering whether or not I should continue...

Because pm is std::shared_ptr<boost::shared_mutex> not std::shared_ptr<boost::shared_mutex>*. You can use this:
readers_writer_vector() :
pm(std::make_shared<boost::shared_mutex>()){}
Anyway, why do you need pointer/smart pointer? This is better fit:
template <class T>
class readers_writer_vector
{
boost::shared_mutex pm;
std::vector<T> data;
public:
void push_back(const T& item){
boost::unique_lock<boost::shared_mutex> lock(pm);
data.push_back(item);
}
};

You're initialising pm with the wrong type; you effectively have
std::shared_ptr<> pm = new std::shared_ptr<>;
You can't assign a shared pointer from a pointer to shared pointer.
Replace the initialiser with
pm(new boost::shared_mutex)
or make the mutex a member directly, rather than using shared pointer.

Related

Pointer to an array of class type and constructor with new

So I am writing a class template and my class contains a pointer to an array that contains instance of class type .
My problem is with constructor of my class.
When in my constructor I use new keyword, it doesn't work properly.
The problem is that my array is not created when I use new in constructor. (It is like it's always a null pointer instead of an array that contains the instances of Node class)
I should also say that there isn't any error.
Here is my code.
#include <iostream>
#include <cstddef>
template <typename V>
class Node {
private:
V _data;
unsigned short _size;
Node<V>* _children;
public:
Node();
Node(V);
Node(V, unsigned short);
Node(const Node&); // copy constructor
~Node();
};
template <typename V>
Node<V>::Node()
: _data(0), _size(0), _children(nullptr) {}
template <typename V>
Node<V>::Node(V data)
: _data(data), _size(0), _children(new Node<V>[_size]) {}
template <typename V>
Node<V>::Node(V data, unsigned short size)
: _data(data), _size(size), _children(new Node<V>[_size]) {}
template <typename V>
Node<V>::Node (const Node& other)
: _size(other._size), _data(other._data) {
_children = new Node<V>[_size];
for (unsigned short i = 0; i < _size; i++)
_children[i] = other._children[i];
}
template <typename V>
Node<V>::~Node() { delete[] _children; }
int main () {
Node<int> n1;
Node<char> n2('A');
Node<char> n3('B', 5);
return 0;
}
Thanks in advenced.
I had copied your code into Visual Studio 2017 CE and placed it in its own header file. When I tried to compile the code as is from your question visual studio was giving me this compiler error:
1>------ Build started: Project: StackOverflow, Configuration: Debug Win32 ------
1>main.cpp
1>c:\users\...\container.h(41): error C2039: '{dtor}': is not a member of 'Node<V>'
1>c:\users\...\container.h(41): error C2447: '{': missing function header (old-style formal list?)
1>Done building project "StackOverflow.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
To fix this compiler error I had to add the declaration of your dtor in the class's declaration itself.
template <typename V>
class Node {
//... previous code
public:
~Node();
};
This allowed me to compile, build and run the code and I ended up with an exit code of 0. It doesn't appear to me that there is anything else wrong with this code from a syntax or compilation viewpoint, but this doesn't mean that there isn't any issues with correctness, efficiency or concerns for memory leaks, dangling pointers etc...
EDIT
After working on this code for a while I had noticed some issues with your existing code:
You had these two constructors declared:
Node(V);
Node(V, unsigned short);
And you had them defined like this:
template <typename V>
Node<V>::Node(V data)
: _data(data), _size(0), _children(new Node<V>[_size]) {}
template <typename V>
Node<V>::Node(V data, unsigned short size)
: _data(data), _size(size), _children(new Node<V>[_size]) {}
The only difference between the two is when the size is 0 or not, otherwise they appear to do the exact same thing. In the first case what does an int data[0] give you? Or what does an array with 0 elements give you?
Another issue concerns the use of your member variables. You are using a prefix _ which is bad code design because those are reserved for either the language and compiler or other things. If you want to distinguish between a member and non member variable. I like to use the post-fix _ instead. Examples: int non_member_varaible; and int member_variable_;.
To clean your code up I removed the extra dependencies of multiple or redundant constructors. I also kept them within the class declaration since this is a class template. I declared the dtor as default. I also removed the use of new and delete by using std::vector and std::shared_ptr. I also added some accessory functions to retrieve the size and the data. I also didn't do anything with the copy constructor and omitted that completely as that should be trivial once you have your class operational.
If you know exactly the size of the array at compile time you can exchange std::vector with std::array and slightly modify the code. If you want this class to have sole ownership of the objects you can replace std::shared_ptr with std::unique_ptr with a few slight modifications.
For demonstration purposes I choose to use std::vector<std::shared_ptr<Node>> as the internal container.
Also instead of trying to add multiple nodes to the constructor; I removed that dependency and just turned it into a function that allows you to add nodes during run time. If you need to add multiple nodes to this class when it is being instantiated then I would suggest using a variadic template constructor. The variadic constructor would also afford you to be able to add any Node type to the container with some slight modifications to the code.
Here is what I have come up with:
container2.h
#pragma once
#include <vector>
#include <memory>
template <typename V>
class Node {
private:
V data_;
std::vector<std::shared_ptr<Node>> children_;
public:
Node() : data_{ 0 } {}
explicit Node(V data) : data_{ data } {}
void add_node(V data) {
auto p = std::make_shared<Node<V>>(Node(data));
children_.push_back(p);
}
~Node() = default;
const size_t size() const { return children_.size(); }
const V data() const { return data_; }
// no bounds checking just for demonstration purposes.
const V data(unsigned index) { return children_[index]->data_; }
};
main.cpp
#include <iostream>
//#include "Container.h"
#include "container2.h"
int main() {
try {
Node<int> n1;
Node<char> n2('A');
Node<char> n3('B');
n3.add_node('C');
n3.add_node('E');
std::cout << n3.size() << '\n';
std::cout << n3.data(1) << '\n';
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
output
2
E
And the code exits with an exit code of 0!

Cannot convert from std::shared_ptr<_Ty> to std::shared_ptr<_Ty>

I am getting the following error:
error C2440: 'static_cast' : cannot convert from 'std::shared_ptr<_Ty>' to 'std::shared_ptr<_Ty> stack\genericstack.h 36 1 Stack
GenericStack.h
#ifndef _GENERIC_STACK_TROFIMOV_H_
#define _GENERIC_STACK_TROFIMOV_H_
#include <memory>
class GenericStack {
struct StackNode {
std::shared_ptr<void> _data;
StackNode* _next;
StackNode(const std::shared_ptr<void>& data, StackNode* next)
: _data(data), _next(next) {
}
};
StackNode* _top;
GenericStack(const GenericStack&);
GenericStack& operator=(const GenericStack&);
protected:
GenericStack();
~GenericStack();
void push(const std::shared_ptr<void>&);
void pop();
std::shared_ptr<void>& top();
bool isEmpty() const;
};
template <class T>
class TStack: private GenericStack {
public:
void push(const std::shared_ptr<T>& p) { GenericStack::push(p); }
void pop() { GenericStack::pop(); }
std::shared_ptr<T> top() { return static_cast<std::shared_ptr<T>>(GenericStack::top()); }
bool empty() const { return GenericStack::isEmpty(); }
};
#endif
GenerickStack.cpp
#include "GenericStack.h"
GenericStack::GenericStack()
:_top(0) {
};
GenericStack::~GenericStack() {
while(!isEmpty()) {
pop();
}
};
void GenericStack::push(const std::shared_ptr<void>& element) {
_top = new StackNode(element, _top);
}
std::shared_ptr<void>& GenericStack::top() {
return _top->_data;
}
void GenericStack::pop() {
StackNode* t = _top->_next;
delete _top;
_top = t;
}
bool GenericStack::isEmpty() const {
return !_top;
}
Main.cpp
#include <iostream>
#include "GenericStack.h"
int main() {
TStack<int> gs;
std::shared_ptr<int> sh(new int(7));
gs.push(sh);
std::cout << *gs.top() << std::endl;
return 0;
}
Why am I getting the error?
I would expect the cast to happen successfully, since with raw pointers I always can case from void* to the real type pointer.
What I want to do here is to create a stack template. But I am trying to reuse as much code as I can, so that templated classes would not swell too much.
Thank you.
You get that error because static_cast requires the types from and to to be convertible. For shared_ptr that will hold only if c'tor overload 9 would participate in overload resolution. But it doesn't, because void* is not implicitly convertible to other object pointer types in C++, it needs an explicit static_cast.
If you want to convert shared pointers based on static_casting the managed pointer types, you need to use std::static_pointer_cast, that is what it's for.
So after plugging that fix
std::shared_ptr<T> top() { return std::static_pointer_cast<T>(GenericStack::top()); }
Your thin template wrapper will build fine.
Take a look at the list of constructors for shared_ptr. You are trying to use overload 9, more specifically the template overload with Y = void and T = int. However, this template overload doesn't participate in overload resolution, because void* is not implicitly convertible to int*. In other words, you cannot convert, even explicitly, shared_ptr<void> to shared_ptr<T> if you cannot implicitly convert void* to T*.
Why not use a template in the first place (move GenericStack functionality into TStack), instead of trying to deal with void*?
But I am trying to reuse as much code as I can, so that templated classes would not swell too much.
By "swell", I assume you mean the template solution would generate too many instances? Do you have any reason to believe that it would indeed be too many?

C++: How to push unique_ptr to deque?

In my project I need container that holds smart pointers to an data unit instances. I write the class (simple example):
template <typename T>
class Queue
{
public:
void push(const T & param)
{
m_deque.push_front(param);
}
private:
std::deque<T> m_deque;
};
Than I want to push the one:
int main()
{
Queue< std::unique_ptr<DataBox> > queue;
std::unique_ptr<DataBox> d1(new DataBox(11));
queue.push(d1);
return 0;
}
And VS2017 compiler says that I can't do this:
Error C2280 std::unique_ptr<DataBox,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
As I understand the reason of the error is attempt to make copy of unique_ptr. But if I change signature to:
void push(T && param) {...}
and the function call
queue.push( std::move(d1) );
I have this error again. So the question is - how should I implement push() that will move unique_ptr to the queue?
You should modify your class to handle move only type:
template <typename T>
class Queue
{
public:
void push(const T & param)
{
m_deque.push_front(param);
}
void push(T&& param)
{
m_deque.push_front(std::move(param));
}
private:
std::deque<T> m_deque;
};
With usage:
int main()
{
Queue< std::unique_ptr<DataBox> > queue;
std::unique_ptr<DataBox> d1(new DataBox(11));
queue.push(std::move(d1));
}
If you would like to make it universal, so that push can take either l or r value you could try something like this:
#include <iostream>
#include <memory>
#include <deque>
#include <utility>
class DataBox
{
public:
DataBox(int i) {}
};
template <typename T>
class Queue
{
public:
template <typename U>
void push(U &&param)
{
m_deque.push_front(std::forward<T>(param));
}
private:
std::deque<T> m_deque;
};
int main()
{
Queue<std::unique_ptr<DataBox>> queue;
std::unique_ptr<DataBox> d1 = std::make_unique<DataBox>(11);
std::unique_ptr<DataBox> d2 = std::make_unique<DataBox>(22);
queue.push(d1);
queue.push(std::move(d2));
return 0;
}
https://ideone.com/ixzEmN
You have the following options.
Option 1: concise and usually fast
template <typename T>
class Queue {
public:
void push(T param) {
m_deque.push_front(std::move(param));
}
private:
std::deque<T> m_deque;
};
I would recommend this for most practical cases, since it's simple. However, if T isn't efficiently movable, it will do two copies instead of one.
Option 2: always fast
template <typename T>
class Queue {
public:
void push(const T& param) {
m_deque.push_front(param);
}
void push(T&& param) {
m_deque.push_front(std::move(param));
}
private:
std::deque<T> m_deque;
};
This is the most optimal solution, but it might be an overkill. If T is efficiently movable (and you should strive to make all types efficiently movable), then it does exactly the same amount of copies as option 1:
Queue<std::vector<int>> q;
std::vector<int> v;
q.push(v); // one copy, both with option 1 and option 2
q.push(std::move(v)); // no copies, both with option 1 and option 2
However:
Queue<NotEfficientlyMovableType> q;
NotEfficientlyMovableType x;
q.push(x); // one copy with option 2, two copies with option 1
q.push(std::move(x)); // same (so it doesn't really make sense)
Option 3: concise, always fast, but has caveats
template <typename T>
class Queue {
public:
template <typename U>
void push(U&& param)
{
m_deque.push_front(std::forward<T>(param));
}
private:
std::deque<T> m_deque;
};
With option 3 you only get to write one function and it always does the minimum number of copies (like option 2). However, it requires template argument deduction, which can break valid code. For example, this works with options 1 and 2, but not with option 3:
Queue<std::pair<int, int>> q;
q.push({1, 2});

MSVC friend function declaration bug

Consider the following piece of code:
#include <cstddef>
template<size_t value> class dummy { };
class my_class
{
int m_member;
// Overload 1
template<size_t value>
friend void friend_func(dummy<value>*);
// Overload 2
template<size_t value>
friend void friend_func(int(*)[value]);
};
// Overload 1
template<size_t value>
void friend_func(dummy<value>*)
{
my_class instance;
instance.m_member = value;
}
// Overload 2
template<size_t value>
void friend_func(int(*)[value])
{
my_class instance;
instance.m_member = value;
}
int main(int argc, char* argv[])
{
dummy<5> d;
friend_func(&d); // call Overload 1
int arr[5];
friend_func(&arr); // call Overload 2 - error in MSVC!
return 0;
}
As you can see, the only difference between these two functions is that the second one takes a pointer to value ints instead of dummy<value>.
This code compiles just fine in GCC ($ gcc-4.7.2 test.cpp) and Clang (thanks WhozCraig), but throws the following error in MSVC (I tested 2012):
1>d:\path\to.cpp(32): error C2248: 'my_class::m_member' : cannot access private member declared in class 'my_class'
1> d:\path\to.cpp(8) : see declaration of 'my_class::m_member'
1> d:\path\to.cpp(7) : see declaration of 'my_class'
1> d:\path\to.cpp(40) : see reference to function template instantiation 'void friend_func<5>(int (*)[5])' being compiled
To me this looks like a bug. However, is there anyone who encountered such a behavior before? Is it really a bug, or maybe there's a particular reason for the error? Any quick workaround for this?
Edit: I've been able to find a proper workaround, see answer below.
It's definitely a bug: A template function parametrized on the size of an array cannot be declared as a friend of a class. It occurs when value is deduced as the size of the array for your friend template function. Here is a shortened version of your code that compiles fine. This example is the exact same code as your example except I specified the size of the array.
class my_class
{
int m_member;
template<size_t value>
friend void friend_func(int(*)[5]);
};
template<size_t value>
void friend_func(int(*)[5])
{
my_class instance;
instance.m_member = value;
}
int main()
{
int arr[5];
friend_func<5>(&arr);
}
One workaround it to pass the value as a second function argument:
template <typename T>
void friend_func(T, int value)
{
my_class instance;
instance.m_member = value;
}
Pretty sure it's a known issue with MSVS. Your specific issue is listed in the Portability Hints: Micrsoft Visual C++ on boost.org.
Look for Templates as Friends. I do not know the work around. However, I think you can make a class a friend. You may be able to use that as a work around.
I've figured a workaround that preserves the functionality yet does its job of preventing the error message. The idea is to use a proxy function and a proxy class to carry the pointer to the array and it's size. Here's the solution:
#include <cstddef>
// Workaround class for a bug in MSVC.
// https://connect.microsoft.com/VisualStudio/feedback/details/717749
// http://stackoverflow.com/questions/15149607
template<class element_type, size_t count>
class friend_declaration_bug_workaround
{
public:
typedef element_type(*ptr_type)[count];
private:
ptr_type m_arr;
public:
explicit friend_declaration_bug_workaround(ptr_type arr)
: m_arr(arr)
{
}
ptr_type value() const
{
return m_arr;
}
};
class my_class
{
int m_member;
friend void friend_func(int*);
template<size_t value>
friend void friend_func_workaround(friend_declaration_bug_workaround<int, value>);
};
template<size_t value>
void friend_func_workaround(friend_declaration_bug_workaround<int, value> workaround)
{
my_class instance;
instance.m_member = (*workaround.value())[0];
}
void friend_func(int* arr)
{
my_class instance;
instance.m_member = *arr;
}
template<size_t value>
void friend_func(int(*arr)[value])
{
friend_declaration_bug_workaround<int, value> workaround(arr);
return friend_func_workaround(workaround);
}
int main(int argc, char* argv[])
{
int value;
friend_func(&value); // call non-templated function
int arr[5];
friend_func(&arr); // call workarounded function
return 0;
}

How bad is to use void pointer in std::vector declaration?

I have two different classes as below:
class text
{ };
class element
{ };
And I want to store them in the class node:
template <typename T>
class node
{
T cargo;
std::vector<void*> children;
node(T cargo) : cargo(cargo)
{ };
void add_child(T node)
{
this->children.push_back((void*) node);
}
}
So I would call the node this way storing both, text and element's:
element div;
text msg;
node<element> wrapper(div);
wrapper.add_child(msg);
EDIT: To get back the content I use T typedef type; and convert void pointer to (type*).
I know that's not very elegant nor functional, but I just can't figure out what's the correct way of doing that. So please tell me if this is practically acceptable and if it is not, how to do that in the proper manner.
Thanks in advance!
#include <vector>
using namespace std;
class Element {};
class Text {};
class Nothing {};
class Node
{
private:
vector< Node* > children_;
protected:
Node() {}
public:
void add( Node* p ) { children_.push_back( p ); }
virtual ~Node() {}
};
template< class Cargo >
class CargoNode
: public Node
{
private:
Cargo cargo_;
public:
CargoNode(): cargo_() {}
};
typedef CargoNode< Element > ElementNode;
typedef CargoNode< Text > TextNode;
typedef CargoNode< Nothing > RootNode;
int main()
{
RootNode* root = new RootNode;
root->add( new ElementNode );
root->add( new ElementNode );
root->add( new TextNode );
root->add( new ElementNode );
// Etc.
}
Cheers & hth.,
PS: Error checking, lifetime management, iteration etc. omitted in this example code.
I would say that void* is nearly always "bad" (for some definition of bad). Certainly, there are likely to be better ways of expressing what it is you're trying to do. If it were me writing this code and I knew the types of the values I was going to put in, then I would consider using a Boost.Variant. If I didn't (for example, this was supplied as a library to someone else to "fill up"), then I would use Boost.Any
For example:
template <class T, class U>
struct node
{
typedef boost::variant<T, U> child_type;
std::vector<child_type> children;
void add_child(T const &t)
{
children.push_back(t);
}
void add_child(U const &u)
{
children.push_back(u);
}
};
...
node<text, element> n;
n.add_child(text("foo"));
A non-boost typed union solution:
struct node
{
struct child
{
int type; // 0 = text; 1 = element
union
{
text* t;
element* e;
} u;
};
std::vector<child> children;
void add_child(text* t)
{
child ch;
ch.type = 0;
ch.u.t = t;
children.push_back(ch);
}
void add_child(element* e)
{
child ch;
ch.type = 1;
ch.u.e = t;
children.push_back(ch);
}
};
Note: you have to be a whole lot more careful about memory management with the typed union.
Define a shared base class for element and text and then add_child can take a pointer to the base class, and the vector can store pointers to the base class.
How would you get them back if you do this? From a void* there is no way to determine what is actually stored on the address.
Edit:
If you always do a cast into T* then you can simply take T* as the parameter.
If your container value is limited to a small number of types, you could achieve this using boost::variant as shown here:
#include <vector>
#include <boost/variant.hpp>
using namespace std;
class text
{ };
class element
{ };
template <typename T>
class node
{
T cargo;
static std::vector<boost::variant<text, element>> children;
node(const T& cargo) : cargo(cargo)
{ };
void add_child(const T& node)
{
children.push_back(boost::variant<text, element>(node));
}
};
I have taken the liberty of suggesting a couple of other mods - use const reference instead of pass-by-value on node constructor and add_child; make the container children static as I don't think it makes sense for each node<T> to have its own container. Locking would be required for multithreaded usage of add_child in this case. These comments apply whether you can use Boost or not in your final solution.
You can perform operations on the vector elements using either get or static_visitor - the latter is preferable since you can make this generic - as shown here. An example of vector iteration analogous to what you would use for this solution:
class times_two_generic
: public boost::static_visitor<>
{
public:
template <typename T>
void operator()( T & operand ) const
{
operand += operand;
cout << operand << endl;
}
};
std::vector< boost::variant<int, std::string> > vec;
vec.push_back( 21 );
vec.push_back( "hello " );
times_two_generic visitor;
std::for_each(
vec.begin(), vec.end()
, boost::apply_visitor(visitor)
);
Output is:
42
hello hello
First, there's no such a thing as "bad" to use a void pointer. Forget all the conventions and bla-blas, and do what's most appropriate for your case.
Now, in you specific case, if there's any connection between those two classes - you may declare a base class, so that those two will inherit it. Then, you may declare the vector of a pointer of that base class.