Ideally I'd want to do something like this, but is this safe/correct? When moving from some_list to other_list, you're editing the contents of some_list, and every subsequent iteration would be invalidated since the objects all contain null contents.
for (auto& object : some_list) {
other_list.emplace_back(std::move(object));
}
Is there any way I could make this code more efficient/safer/better or is this the best way I can possibly do this?
Merely modifying the contained objects doesn't invalidate iterators, so this code is safe. There's no need to write the loop yourself, though, since there's the std::move algorithm:
#include <algorithm>
#include <iterator>
template<typename InContainer, typename OutContainer>
void append_back(InContainer& some_list, OutContainer& other_list)
{
using std::begin;
using std::end;
std::move(begin(some_list), end(some_list), std::back_inserter(other_list);
some_list.clear();
}
Related
I wonder how to get access to element of list that contains pointers to objects. I want to achieve that without dereferencing. Propably it will be much easier if i just show what i want. So I have list:
list<ObjectClass*> nameOfObject;
and I have method:
bool collision(list<ObjectClass*>::iterator&);
And inside definition of that method I have:
{
if((*nameOfObject)->getSprite()) return true;
else return false;
}
What i want is to getSprite without needing to dereference nameOfObject inside method, so something like that:
{
if((nameOfObject)->getSprite()) return true;
else return false;
}
Everything that i tried is not working. I thought that it would be easy but i really don;t get it. Any ideas? I will add that list has to contain pointer to the objects, because of polimorphysm.
list<ObjectClass*>::iterator&
It's unclear why iterator is passed by reference.
*nameOfObject
This is ill-formed because std::list doesn't have indirection operator. I suspect that you may have shadowed that variable, and forgotten to include the shadowing variable in the example.
What i want is to getSprite without needing to dereference nameOfObject inside method,
Then you need to have an instance of a class with getSprite member function in the class rather than a pointer/iterator to such. If you do have a pointer/iterator, then there is no way to access the pointed object through the pointer without indirection.
so something like that:
(nameOfObject)->getSprite()
That does dereference nameOfObject. -> is the indirecting member access operator. It is also ill-formed with a list.
Any ideas?
Avoid wanting impossible things ¯\_(ツ)_/¯
You usually don't pass single iterator around.
If you want single object, pass single object (whether by reference or pointer)
I write an example code, hope it helps.
fIter is probably what most close to what you currently have
f is demonstrate you can iterate collection without directly use iterator
//
// https://stackoverflow.com/q/63156916/5980430
//
#include <list>
#include <iostream>
class ObjectClass{
public:
int spriteID;
int getSprite(){return spriteID;}
};
//your *collision* function
void collision(ObjectClass& obj){
std::cout << obj.getSprite() << '\n';
}
void f(std::list<ObjectClass>& objs){
for (auto& obj : objs){
collision(obj);
}
}
//even with iterator, you dereference it before pass in other functions
void fIter(std::list<ObjectClass>& objs){
for (auto it = objs.begin(); it != objs.end(); ++it){
collision(*it);
}
}
int main(){
std::list<ObjectClass> objects;
objects.push_back({1});
objects.push_back({2});
objects.push_back({3});
f(objects);
fIter(objects);
}
https://wandbox.org/permlink/SgI5ibjaIXd644DH
What is the most correct and efficient way to std::move elements from a vector of a certain type (T1) into a vector of an std::pair of that same type (T1) and another type (T2)?
In other words, how should I write MoveItems()?
#include <iostream> // For std::string
#include <string> // For std::string
#include <vector> // For std::vector
#include <utility> // For std::pair
using std::vector;
using std::string;
using std::pair;
vector<string> DownloadedItems;
vector<pair<string,bool>> ActiveItems;
vector<string> Download()
{
vector<string> Items {"These","Words","Are","Usually","Downloaded"};
return Items;
}
void MoveItems()
{
for ( size_t i = 0; i < DownloadedItems.size(); ++i )
ActiveItems.push_back( std::pair<string,bool>(DownloadedItems.at(i),true) );
}
int main()
{
DownloadedItems = Download();
MoveItems();
return 0;
}
Thank you for your time and help, I truly appreciate it!
void MoveItems()
{
ActiveItems.reserve(DownloadedItems.size());
for (auto& str : DownloadedItems)
ActiveItems.emplace_back(std::move(str), true);
}
N.B.: For strings as small as the ones in your example, moving may have the same cost as copying due to SSO, or perhaps even slightly more expensive if the implementation decides to empty out the source anyway.
Some things you can do:
At the start of MoveItems(), call ActiveItems.reserve(DownloadedItems.size());. This prevents your array from resizing while you push things into it.
Instead of calling push_back call emplace_back. Here is an explanation of the advantages of doing so.
Worth noting, in this example, you can stop the copy into a new data structure by just constructing the std::pair from the start, and not copying data.
Consider How do I write a range pipeline that uses temporary containers?. The question is how to build a view transforming each element T using some given function
std::vector<T> f(T t);
while complying with the restriction (borrowing from the top answer there) that
A view is a lightweight wrapper that presents a view of an underlying sequence of elements in some custom way without mutating or copying it. Views are cheap to create and copy, and have non-owning reference semantics.
Basically, all answers there seem to agree that, due to this restriction, it can't be done via a view.
I don't understand how this fits in with the library supporting partial_sum.
Consider the following glorified integer:
#include <vector>
#include <iostream>
#include <memory>
#include <range/v3/all.hpp>
using namespace ranges;
struct glorified_int {
explicit glorified_int(int i) : m_i{std::make_shared<int>(i)} {}
operator int() const { return *m_i; }
std::shared_ptr<int> m_i;
};
glorified_int operator+(const glorified_int &lhs, const glorified_int &rhs) {
glorified_int ret{(int)lhs + (int)rhs};
return ret;
}
It basically just wraps up an int in a class storing it in an std::shared_ptr, allowing to initialize, extract, and add. W.r.t. non-owning reference semantics, I can't see the fundamental difference between it and a container such as std::vector.
Range doesn't seem to have a problem applying partial_sum to this, though:
int main() {
std::vector<glorified_int> vi{ glorified_int{1}, glorified_int{2} };
for(const auto &ps: vi | view::partial_sum())
std::cout << ps << std::endl;
Prints out
$ ./a.out
1
3
Isn't (the glorified integer of) 3 a temporary here? It's certainly not part of the original sequence. Also, a partial sum is a stateful transformation, obviously, so how can range guarantee that
Views are cheap to create and copy, and have non-owning reference semantics.
The view is as expensive to copy as the accumulation object.
Note that there's also no problem to chain this further (i.e., it is not an action):
vi | view::partial_sum() | view::take(10);
What is the difference, then?
Full Code
#include <vector>
#include <iostream>
#include <memory>
#include <range/v3/all.hpp>
using namespace ranges;
struct glorified_int {
explicit glorified_int(int i) : m_i{std::make_shared<int>(i)} {}
operator int() const { return *m_i; }
std::shared_ptr<int> m_i;
};
glorified_int operator+(const glorified_int &lhs, const glorified_int &rhs) {
glorified_int ret{(int)lhs + (int)rhs};
return ret;
}
int main() {
std::vector<glorified_int> vi{ glorified_int{1}, glorified_int{2} };
for(const auto &ps: vi | view::partial_sum())
std::cout << ps << std::endl;
vi | view::partial_sum() | view::take(10);
}
What makes a view a view is that it doesn't take or require ownership of, copy, or modify any of the elements of the input range. But a view isn't required to have no state whatsoever. Even take() or filter() have some state (a counter and a predicate, respectively).
In this specific case, partial_sum doesn't have to own any of the elements of the input range. That's the input range's job. It also doesn't need to copy or modify them. It merely needs to keep track of its own state - the running sum (an optional<glorified_int>) and the binary function doing the summing (a plus). It owns one of its own objects, but that object exists outside of the input range entirely. That still makes it a view, just a stateful one.
You write:
The view is as expensive to copy as the accumulation object.
This is true. But that's also true of many views. transform() is as expensive to copy as the function we're using to transform the view, maybe you have an enormous stateful, expensive, memory-allocating monstrosity.
When Eric writes about cheap to create and copy, I believe he means in the context of creating and copying the entire input range to produce a new range. While partial_sum() needs to keep the running sum, which in your case isn't cheap since that element needs allocation, that's still far cheaper than writing an action-based partial_sum:
// cheap version
for(const auto &ps: vi | view::partial_sum()) { ... }
// expensive version
std::vector<glorified_int> partial_sums;
if (!vi.empty()) {
auto it = vi.begin();
partial_sums.emplace_back(*it++);
for (; it != vi.end(); ++it) {
partial_sums.emplace_back(*it + partial_sums.back());
}
}
for (const auto &ps : partial_sums) { ... }
We obviously don't need the entire partial_sums vector to do what we want (if we did need it, well, no way around that). The view offers us a cheap way to, well, view the partial sums.
I would like to replace the following code with std::lock():
for (mutex* m : mutexes) {
m->lock();
}
Is there anyway I could invoke std::lock () on those mutexes given a std::vector<mutex*>?
Unfortunately the standard library doesn't provide an overload for std::lock that takes a pair of iterators pointing to lockable objects. To use std::lock you must know the number of lockable objects at compile time, and pass them as arguments to the function. However, Boost does provide an overload that takes iterators, and it'll work with std::mutex.
The other piece of scaffolding you'll need is boost::indirect_iterator; this will apply an extra dereference when you dereference the iterator (needed because you have std::vector<std::mutex*> and not std::vector<std::mutex>. The latter would not be very useful anyway since std::mutex cannot be copied or moved.)
#include <boost/thread/locks.hpp>
#include <boost/iterator/indirect_iterator.hpp>
#include <vector>
#include <mutex>
int main()
{
using mutex_list = std::vector<std::mutex*>;
mutex_list mutexes;
boost::indirect_iterator<mutex_list::iterator> first(mutexes.begin()),
last(mutexes.end());
boost::lock(first, last);
}
Live demo
I have:
vector of unique_ptrs of ObjectA
vector of newly default constructed vector of ObjectB, and
a function in Object B that has signature void f(unique_ptr<ObjectA> o).
(word Object omitted from here on)
How do I do Bvec[i].f(Avec[i]) for all 0 < i < length in parallel?
I have tried using transform(Bvec.begin(), Bvec.end(), A.begin(), B.begin(), mem_fun_ref(&B::f)), but it gives a bunch of errors and I'm not sure if it would even pass the right A as parameter, let alone allow me to move them. (&B::f(A.begin()) would not work as the last parameter either.
I have also thought of using for_each and then a lambda function, but not sure how to get the corresponding element. I thought of incrementing a counter, but then I don't think that parallelizes well (I could be wrong).
I can, of course, use a for loop from 0 to end, but I am pretty sure there is a simple thing I'm missing, and it is not parallel with a simple for loop.
Thanks.
Here is a non-parallel implementation using a handmade algorithm. I'm sure someone more versed in the functional could come up with a more elegant solution. The problem with transform is, that we cannot use it with functions that return void and I can't remember another stdlib function that takes two ranges and apply them to each other. If you really want to parallelize this, it needs to be done in the apply_to function. Launching an async task (e.g. std::async(*begin++, *begin2++) could work, although I have no experience with this and cannot get it to work on gcc 4.6.2.
#include <iterator>
#include <memory>
#include <vector>
#include <algorithm>
#include <functional>
// this is very naive it should check call different versions
// depending on the value_type of iterator2, especially considering
// that a tuple would make sense
template<typename InputIterator1, typename InputIterator2>
void apply_to(InputIterator1 begin, InputIterator1 end, InputIterator2 begin2) {
while(begin != end) {
(*begin++)(*begin2++);
}
}
struct Foo {
};
struct Bar {
void f(std::unique_ptr<Foo>) { }
};
int main()
{
std::vector< std::unique_ptr<Foo> > foos(10);
std::vector< Bar > bars(10);
std::vector< std::function<void(std::unique_ptr<Foo>) > > funs;
std::transform(bars.begin(), bars.end(), std::back_inserter(funs),
// non-const due to f non-const, change accordingly
[](Bar& b) { return std::bind(&Bar::f, &b, std::placeholders::_1); });
// now we just need to apply each element in foos with funs
apply_to(funs.begin(), funs.end(), std::make_move_iterator(foos.begin()));
return 0;
}