1

I have a list of objects:

std::list<A> objects;

In order to trigger an async operation that will remove them from the list based on some condition, The objects need to be aware of their location in the list:

A::A(std::list<A>::iterator it);

How can I pass iterator to constructor when adding items to the list?

objects.emplace(<the iterator to new item>);

Initializing the member iterator of class A cannot be done later, even the constructor may trigger the deletion operation, so it needs this member while construction.

Possible solutions that I have thought (brings extra complexity):

1:

objects.emplcae(A(objects.end())); // dummy object
A a{ std::prev(objects.end()) };
std::swap(a, object.back());

2:

objects.emplace();
objects.back().set_iterator(std::prev(objects.end()));
objects.back().run(); // Moved the work from constructor to this function (against RAII)

3: Try to get iterator based on the address of this.

Null
  • 349
  • 2
  • 12
  • Have you considered alternatives where the objects don't have to remove themselves from the list? Also, `std::list` is not inherently thread-safe, so you might not be able to have an object safely remove itself if it is run asynchronously. – G. Sliepen Jun 17 '20 at 18:18
  • Yes, in my current implementation objects don't remove themselves and I need to trigger remove operation in the list once in a while and it needs to iterate through all. My Async model is using asio io_context and I run it from single thread, so all handlers will run in a single thread. If I had ran it from multiple threads, then I would need to handle thread safety. – Null Jun 17 '20 at 20:16
  • Why cannot we get the iterator from the address of object? I thought list item is the objects followed by two pointers to prev and next, and iterator is a pointer to this object. – Null Jun 17 '20 at 20:24
  • 1
    An iterator may or may not be implemented as a pointer to an object. And the end pointer for sure doesn't point to an item that is in the list. – G. Sliepen Jun 17 '20 at 20:33

1 Answers1

3

There is a chicken and egg problem that you have to resolve: the A class wants the iterator to be ready before the object is constructed, while the iterator assumes that some sort of an element is constructed already.

One way to solve this problem is to introduce an additional level of indirection, for example to store not the instances of A but the pointers (smart pointers) instead. Another way is to use placement new: first to allocate an item in list without constructing the object (just allocate the memory), then construct the object inplace with the iterator provided. The simplest solution would be to separate in time the construction of A and setting the iterator (A::setIterator(std::list<A>::iterator&) method).

I would also recommend you to implement that as a Factory method that takes a list (an all the ingredients), and does all this error-prone stuff in one place. The Factory method should be the friend of A while the constructor A::A should be private. This would prevent you from other incorrect ways to construct A.

Dmitry Kuzminov
  • 6,180
  • 6
  • 18
  • 40
  • I like the idea of allocating then creating in place using new in-place. https://stackoverflow.com/questions/3763846/what-is-an-in-place-constructor-in-c – Null Jun 17 '20 at 20:26