I have this program that I downloaded from the internet. If I add the clear at the end, it crashes with this message:
idf#idf-Satellite-C55t-A ~/Documents/BOOST_INTRUSIVE/Intrusive1/bin/Debug $ ./Intrusive1
Intrusive1: /usr/local/include/boost/intrusive/detail/utilities.hpp:366: void boost::intrusive::detail::destructor_impl(Hook&, boost::intrusive::detail::link_dispatch<(boost::intrusive::link_mode_type)1u>) [with Hook = boost::intrusive::generic_hook<boost::intrusive::get_list_node_algo<void*>, boost::intrusive::member_tag, (boost::intrusive::link_mode_type)1u, (boost::intrusive::base_hook_type)0u>]: Assertion `!hook.is_linked()' failed.
Aborted
idf#idf-Satellite-C55t-A ~/Documents/BOOST_INTRUSIVE/Intrusive1/bin/Debug $
Not sure what that all means. I am hoping to clear all the items, and that the contents get deleted.
#include <vector>
#include <iostream>
#include <boost/intrusive/list.hpp>
using namespace boost::intrusive;
class MyClass : public list_base_hook<> //This is a derivation hook
{
int anInt;
public:
//This is a member hook
list_member_hook<> member_hook_;
MyClass(int i)
: anInt(i)
{}
};
//Define a list that will store MyClass using the public base hook
typedef list<MyClass> BaseList;
//Define a list that will store MyClass using the public member hook
typedef list< MyClass
, member_hook< MyClass, list_member_hook<>, &MyClass::member_hook_>
> MemberList;
int main()
{
typedef std::vector<MyClass>::iterator VectIt;
//Create several MyClass objects, each one with a different value
std::vector<MyClass> values;
for(int i = 0; i < 100; ++i)
values.push_back(MyClass(i));
BaseList baselist;
MemberList memberlist;
//Now insert them in the reverse order in the base hook list
for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it)
baselist.push_front(*it);
//Now insert them in the same order as in vector in the member hook list
for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it)
memberlist.push_back(*it);
//Now test lists
{
BaseList::reverse_iterator rbit(baselist.rbegin());
MemberList::iterator mit(memberlist.begin());
VectIt it(values.begin()), itend(values.end());
//Test the objects inserted in the base hook list
for(; it != itend; ++it, ++rbit)
if(&*rbit != &*it) return 1;
//Test the objects inserted in the member hook list
for(it = values.begin(); it != itend; ++it, ++mit)
if(&*mit != &*it) return 1;
values.clear();
//Now delete all the values. Do they dissapear from all containers?
//Now insert them in the reverse order in the base hook list
//for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it)
// ;
//std::cout << values.size();
//std::cout << baselist.size();
//std::cout << memberlist.size();
}
return 0;
}
Intrusive containers don't own their elements. The elements must be stored out-of-band.
What you're doing is delete the elements, while they're still logically inserted into (several) intrusive collections (i.e. they are linked through their intrusive hooks).
In safe mode, Boost Intrusive will actually diagnose this in the destructor of the hook structs, which is why you get the error message.
See also: auto-unlink hooks
Related
I'm working on a self imposed challenge which involves implementing a linked list and an append function for it, which is giving me issues seemingly related to variable scope.
The append function loops through each link element until it reads a NULL value and then changes the data value associated with that link to the function input. The test outputs within the function seem to show it is working as intended, but when performing the same test outside the function, even after it is called gives a different output.
template <class T>
struct atom{
T data;
atom<T>* link = NULL;
};
template <class T>
void append_LL(atom<T> first, T input_data){
atom<T>* current_node = &first;
atom<T>* next_node = current_node->link;
int i = 0;
while (i < 4 && next_node != NULL) {
current_node = next_node;
next_node = next_node->link;
i ++;
}
current_node->data = input_data;
current_node->link = (atom<T>*)malloc(sizeof(atom<T>));
cout << "leaving node as: " << current_node->data << endl; //outputs 5
cout << "input nodes data: " << first.data << endl; //outputs 5
}
int main() {
int dd = 5;
atom<int> linked_list;
linked_list.data = 999;
append_LL(linked_list, dd);
cout << linked_list.data << endl; //outputs 999
}
Because you are not sending the same atom. You see the program is making a copy of the linked_list in the main function and sending that copy to the function.
If you want to modify the same linked_list then change
void append_LL(atom<T> first, T input_data){
to
void append_LL(atom<T> &first, T input_data){
That way you are sending the really atom not a copy of it.
I am using the type std::valarray<std::valarray<double>> and wish to sum each of the contained valarrays element wise, to leave a std::valarray<double>.
The C++ documentation states that the operator .sum() can be applied to std::valarray<T> so long as the operator += is defined for type T. My code below (method1) tries to apply this to std::valarray<std::valarray<double>>, but the result appears to be nonsense.
However if I perform this manually, using the += operator (method2), I get the result I want. But the fact that method2 works seems to imply that the operator += is defined for the type std::valarray<double>, and hence that method1, using .sum(). should work. I really can't understand what is happening here...
My code:
#include <iostream>
#include <valarray>
// Attempt to use .sum() operator
std::valarray<double> method1(const std::valarray<std::valarray<double>>& data) {
return data.sum();
}
// Manual summation using += operator
std::valarray<double> method2(const std::valarray<std::valarray<double>>& data) {
std::valarray<double> sum(data[0].size());
for (size_t i{0}; i < data.size(); i++) {
sum += data[i];
}
return sum;
}
// Display size and elements
void showData(const std::valarray<double> data) {
std::cout << "Size = " << data.size() << "\n";
std::cout << "Data = ";
for (size_t i{0}; i < data.size(); i++) {
std::cout << data[i] << " ";
}
std::cout << "\n\n";
}
int main() {
std::valarray<std::valarray<double>> data{{1,2},{3,4}};
showData(method1(data));
showData(method2(data));
}
My output:
Size = 0
Data =
Size = 2
Data = 4 6
The sum method of std::valarray requires operator+= to be defined for its value type (in your case, std::valarray), but std::valarray also requires it to be default-constructible (from the "Numeric" concept requirement).
This allows the sum method to work without operator+, by first default-constructing an element, and then adding each contained element with operator+=.
Although it isn't defined anywhere, as far as I know, it probably works something like this.
T sum() const {
T result;
for (auto& it : elements) {
result += it;
}
return result;
}
The problem with a valarray of valarrays (std::valarray<std::valarray>) is that a default-constructed valarray is empty. And when operator+= is applied with an empty valarray and a non-empty one, it results in undefined behavior ("The behavior is undefined if size() != v.size()"). What you are likely to get is an empty valarray as a result (but you could potentially get anything).
What you could use instead is std::accumulate. It requires an initial value as third parameter, which takes care of the problem.
std::accumulate(std::begin(data), std::end(data), std::valarray<double>(data[0].size()))
Live on Coliru.
PS: don't ask me why std::valarray has no method begin and end.
I'm facing a problem that may be a misunderstanding of what this sentence really means "An application just needs to call event_dispatch() and then add or remove events dynamically without having to change the event loop." or I can't find the right documentation of how to do it.
Well, the problem is that I think that I should be able to add events to the event loop after running it with event_dispatch() but I can't get it working. Here is the code:
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <stdio.h>
static int n_calls = 0;
static int n_calls2 = 0;
void cb_func(evutil_socket_t fd, short what, void *arg)
{
struct event *me = arg;
printf("cb_func called %d times so far.\n", ++n_calls);
if (n_calls > 100)
event_del(me);
}
void cb_func2(evutil_socket_t fd, short what, void *arg)
{
struct event *me = arg;
printf("cb_func2 called %d times so far.\n", ++n_calls2);
if (n_calls2 > 100)
event_del(me);
}
int main(int argc, char const *argv[])
{
struct event_base *base;
enum event_method_feature f;
base = event_base_new();
if (!base) {
puts("Couldn't get an event_base!");
} else {
printf("Using Libevent with backend method %s.",
event_base_get_method(base));
f = event_base_get_features(base);
if ((f & EV_FEATURE_ET))
printf(" Edge-triggered events are supported.");
if ((f & EV_FEATURE_O1))
printf(" O(1) event notification is supported.");
if ((f & EV_FEATURE_FDS))
printf(" All FD types are supported.");
puts("");
}
struct timeval one_sec = { 1, 0 };
struct timeval two_sec = { 2, 0 };
struct event *ev;
/* We're going to set up a repeating timer to get called called 100 times. */
ev = event_new(base, -1, EV_PERSIST, cb_func, NULL);
event_add(ev, &one_sec);
event_base_dispatch(base);
// This event (two_sec) is never fired if I add it after calling event_base_dispatch.
// If I add it before calling event_base_dispatch it works as the other event (one_sec) also does.
ev = event_new(base, -1, EV_PERSIST, cb_func2, NULL);
event_add(ev, &two_sec);
return 0;
}
I see it now... I don't know why but I was thinking that the event-loop started running in another thread or something like that. I see now that what I was trying to do has no sense. You can add events inside the callbacks, that is, when the loop is running. When you start the event-loop, it never returns so everything after that will never be called (unless you stop the event-loop)
I was trying to implement singly linked list using share_ptr. Here is the implementation...
Below is the node class...
template<typename T>
class Node
{
public:
T value;
shared_ptr<Node<T>> next;
Node() : value(0), next(nullptr){};
Node(T value) : value(value), next(nullptr){};
~Node() { cout << "In Destructor: " << value << endl; };
};
Below is the linked list class...
template<typename T>
class LinkedList
{
private:
size_t m_size;
shared_ptr<Node<T>> head;
shared_ptr<Node<T>> tail;
public:
LinkedList() : m_size(0), head(nullptr) {};
void push_front(T value)
{
shared_ptr<Node<T>> temp = head;
head = make_shared<Node<T>>(Node<T>(value));
head->next = temp;
m_size++;
if (m_size == 1)
tail = head;
}
void pop_front()
{
if (m_size != 0)
{
// Here I am having doubt------------------------!!!
//shared_ptr<Node<T>> temp = head;
head = head->next;
m_size--;
if (m_size == 0)
tail = nullptr;
}
}
bool empty()
{
return (m_size == 0) ? true : false;
}
T front()
{
if (m_size != 0)
return head->value;
}
};
My question is, am I using the shared_ptr properly for allocating a node? If not, how should I use the shared_ptr to allocate and how should I delete the node in the pop_front method?
I believe this belongs on code review.
Most importantly: Why are you using shared_ptr? shared_ptr means the ownership of an object is unclear. This is not the case for linked lists: Every node owns the next. You can express that using unique_ptr which is easier and more efficient.
pop_front seems to be functioning correctly. You may consider throwing an exception or an assertion instead of doing nothing when using pop_front on an empty list.
front is more problematic. If the list is empty you most likely get a garbage object.
What is the significance of tail? It does not seem to be used for anything and since you cannot go backwards there is no real point to getting the tail.
make_shared<Node<T>>(Node<T>(value)) should be make_shared<Node<T>>(value) instead. make_shared<Node<T>>(value) creates a Node using value as the parameter for the constructor. make_shared<Node<T>>(Node<T>(value)) creates a Node with value as the parameter and then creates a new Node with the temporary Node as parameter and then destroys the first Node.
You are missing the copy and move constructor and assignment and move assignment operators.
After you are satisfied with your list implementation consider using std::forward_list instead.
I am trying to make the producer-consumer method using c++11 concurrency. The wait method for the condition_variable class has a predicate as second argument, so I thought of using a lambda function:
struct LimitedBuffer {
int* buffer, size, front, back, count;
std::mutex lock;
std::condition_variable not_full;
std::condition_variable not_empty;
LimitedBuffer(int size) : size(size), front(0), back(0), count(0) {
buffer = new int[size];
}
~LimitedBuffer() {
delete[] buffer;
}
void add(int data) {
std::unique_lock<std::mutex> l(lock);
not_full.wait(l, [&count, &size]() {
return count != size;
});
buffer[back] = data;
back = (back+1)%size;
++count;
not_empty.notify_one();
}
int extract() {
std::unique_lock<std::mutex> l(lock);
not_empty.wait(l, [&count]() {
return count != 0;
});
int result = buffer[front];
front = (front+1)%size;
--count;
not_full.notify_one();
return result;
}
};
But I am getting this error:
[Error] capture of non-variable 'LimitedBuffer::count'
I don't really know much about c++11 and lambda functions so I found out that class members can't be captured by value. By value though, I am capturing them by reference, but it seems like it's the same thing.
In a display of brilliance I stored the struct members values in local variables and used them in the lambda function, and it worked! ... or not:
int ct = count, sz = size;
not_full.wait(l, [&ct, &sz]() {
return ct != sz;
});
Obviously I was destroying the whole point of the wait function by using local variables since the value is assigned once and the fun part is checking the member variables which may, should and will change. Silly me.
So, what are my choices? Is there any way I can make the wait method do what it has to do, using the member variables? Or I am forced to not use lambda functions so I'd have to declare auxiliary functions to do the work?
I don't really get why I can't use members variables in lambda functions, but since the masters of the universe dessigned lamba functions for c++11 this way, there must be some good reason.
count is a member variable. Member variables can not be captured directly. Instead, you can capture this to achieve the same effect:
not_full.wait(l, [this] { return count != size; });