Simplest way to assign std::span to std::vector - c++

I wanted to do this
#include <vector>
#include <span>
struct S
{
std::vector<int> v;
void set(std::span<int> _v)
{
v = _v;
}
};
But it does not compile. What are the alternatives?

v.assign(_v.begin(), _v.end());

You can also use the std::vector::insert as follows:
v.insert(v.begin(), _v.begin(), _v.end());
Note that, if the v should be emptied before, you should call v.clear() before this. However, this allows you to add the span to a specified location in the v.
(See a demo)

Related

Moving an std::unordered_map values to std::vector

Is there any way to move unordered_map values to a vector? All the ways I was able to find copy values (like in my example) instead of using something similar to std::move.
I would like to not copy values so I can retain uniqueness of shared_ptr foo, which I'll later change to unique_ptr.
class Class {
public:
std::shared_ptr <int> foo = std::shared_ptr <int> (new int (5));
};
int main() {
std::unordered_map <int, Class> mapOfObjects({
{1, Class()},
{2, Class()},
{3, Class()},
{4, Class()},
{5, Class()} });
std::vector <Class> someVector;
for (auto &object : mapOfObjects) {
someVector.push_back(object.second);
std::cout << "Is unique? " << ( someVector.back().foo.unique() ? "Yes." : "No.")
<< std::endl << std::endl;
}
}
Thank you in advance for all helpful answers.
You can certainly move shared_ptr from unordered_map to vector. All you need to do is to use std::move in your example:
someVector.push_back(std::move(object.second));
Keep in mind, after this operation, you might want to clear the map, as it now contains empty objects.
#SergeyA's answer already covers the essential part here, let me nevertheless add a solution based on range-v3, it shows where one part of the language is heading to with C++20.
#include <range/v3/view/map.hpp>
#include <range/v3/view/move.hpp>
using namespace ranges;
/* Setup mapOfObjects... */
const std::vector<Class> someVector = mapOfObjects | view::values | view::move;
The STL in its current shape isn't that bad either, but admittetly more verbose:
#include <algorithm>
#include <iterator>
std::vector<Class> someVector;
std::transform(std::move_iterator(mapOfObjects.begin()),
std::move_iterator(mapOfObjects.end()),
std::back_inserter(someVector),
[](std::pair<int, Class>&& entry){ return std::move(entry.second); });

Insert custom class with template into std::map

I have written my own class and I want to insert it into a map. See the example below:
#include <iostream>
#include <string>
#include <map>
#include <memory>
#include <mutex>
template <class T>
class A {
public:
T a;
A() = default;
~A() = default;
A(T i) { a = i; }
};
int main()
{
std::pair<int,A<int>> p;
p = std::make_pair<int,A<int>>(9,A<int>(1));
std::map<int, A<int>> m;
m.emplace(1,A<int>(1));
}
When I try to compile this, I get an enormous error. Please help interpret it. :)
See error here:
http://cpp.sh/9nc35
EDIT:
I had the typo, thanks! Though, the other problem I was struggling with first arose now. Seems like it is because of the mutex? Why?
Your map is defined as:
std::map<int, std::unique_ptr<A<int>>>
But in the next line you're trying to pass an std::pair<int, A<int>> to m.emplace() as the key.
I think you just want to do:
m.emplace(9, std::make_unique<A<int>>(1));
// ^
// Not `p`
You are trying to insert/emplace pair (pair<...>, A) into your map, while you've specified it's key as an int. You most-likely want m.emplace(9,std::make_unique<A<int>>(1)); (see 9 instead of p) or just m.insert(p); (would work fine in your cpp.sh).
Furthermore, your use of unique_ptr here is most-likely wrong/unwarranted and only complicates things. See fixed up example here: http://cpp.sh/3d2hw
Also, you may study STL collections/see some basic examples over at https://en.cppreference.com (https://en.cppreference.com/w/cpp/container/map/map for some map construction examples).

Copy/wrap vector<Class*> to vector<Class>

Is there an std function to easily copy a vector of pointers to classes into a vector of classes or do I have to manually iterate over them?
Looking for the solution with the fastest/fewer lines of code :).
A solution that avoids copying without leaking memory is also welcomed!
I doubt there is such, below is one liner with for:
std::vector<X*> vec1 = { new X, new X };
std::vector<X> vec2;
vec2.reserve(vec1.size());
for (auto p : vec1) vec2.push_back(*p);
if you want to make sure no copies are made then you can use std::reference_wrapper<>:
std::vector<std::reference_wrapper<X>> vec2;
for (auto p : vec1) vec2.push_back(*p);
but then you have to make sure no element of vec2 is accessed after vec1 elements were deallocated.
Another aproach is to use unique_ptr like that:
std::vector<std::unique_ptr<X>> vec2;
for (auto p : vec1) vec2.emplace_back(p);
now you can ditch vec1, but then why not make vec1 of type std::vector<std::unique_ptr<X>>?
A one-liner with no manual iteration at all:
std::for_each(vec1.begin(), vec1.end(), [&](auto x) { vec2.push_back(*x); });
(Disclaimer: I'm not 100% sure about the reference-capturing lambda syntax.)
You have to do it yourself. std:transform or std::for_each will help you:
#include <algorithm>
#include <vector>
#include <functional>
using namespace std::placeholders;
class Myclass{};
Myclass deref(const Myclass *mc) { return *mc;}
void append(std::vector<Myclass> &v, Myclass *mc) {v.push_back(*mc);}
int main(){
std::vector<Myclass*> foo;
std::vector<Myclass> bar;
/* foo is initialised somehow */
/* bar is initialised somehow to hold the same amount of dummy elements */
//solution with transform
std::transform (foo.begin(), foo.end(), bar.begin(), deref);
bar={};
// solution with for_each
auto bound_append = std::bind(append, bar, _1);
std::for_each(foo.begin(), foo.end(), bound_append);
}
Compile wit -std=c++11 (gcc).

class with unique_ptr problems

When using emplace_back a constructor must exist for the parameters passed (k,v) thus I need the constructor below. However since I use unique_ptr it complains about not being able to access 'delete' which I believe means I'm doing something that allows me to have more then one pointer.
I can't figure out the syntax. How do I write this constructor the right way?
struct KV{
unique_ptr<string> k, v;
KV(){}
KV (unique_ptr<string> k_,unique_ptr<string> v_):k(move(k_)),v(move(v_)){}
};
Your constructor is OK. A possible problem is that you are not moving the two unique_ptrs when supplying them to your constructor:
#include <memory>
#include <string>
using namespace std;
struct KV{
unique_ptr<string> k, v;
KV(){}
KV (unique_ptr<string> k_,unique_ptr<string> v_):k(move(k_)),v(move(v_)){}
};
int main()
{
unique_ptr<string> p1(new string());
unique_ptr<string> p2(new string());
// KV v(p1, p2); // ERROR!
KV kv(move(p1), move(p2)); // OK
vector<KV> v;
v.emplace_back(move(p1), move(p2)); // OK
}
UPDATE:
When VS2012 was shipped, VC11 did not support variadic templates. The correct implementation of emplace_back() should be variadic, but MS provided a dummy one. When the CTP has been shipped, only the compiler has been updated with support for variadic templates, but the STL hasn't been updated. Therefore, you still get the error.
There is not much to do about this if you can't change your compiler, apart from waiting for the next release of the product to be shipped. In the meanwhile, avoid using emplace_back() and use push_back() instead.
You haven't mentioned what container you're trying to emplace_back into, but assuming it is a vector, if your KV struct is really that simple, there's no need to declare any constructors. Just use aggregate initialization.
#include <memory>
#include <string>
#include <utility>
#include <vector>
using namespace std;
struct KV
{
unique_ptr<string> k, v;
// KV(){}
// KV (unique_ptr<string> k_,unique_ptr<string> v_):k(move(k_)),v(move(v_)){}
};
int main()
{
unique_ptr<string> p1(new string());
unique_ptr<string> p2(new string());
KV v{move(p1), move(p2)}; // initialize an instance
// this step is not necessary, you can skip it
vector<KV> vec;
vec.emplace_back(KV{move(v.k), move(v.v)});
}

How can I return a copy of a vector containing elements not in a set?

Suppose I have the following two data structures:
std::vector<int> all_items;
std::set<int> bad_items;
The all_items vector contains all known items and the bad_items vector contains a list of bad items. These two data structures are populated entirely independent of one another.
What's the proper way to write a method that will return a std::vector<int> contain all elements of all_items not in bad_items?
Currently, I have a clunky solution that I think can be done more concisely. My understanding of STL function adapters is lacking. Hence the question. My current solution is:
struct is_item_bad {
std::set<int> const* bad_items;
bool operator() (int const i) const {
return bad_items.count(i) > 0;
}
};
std::vector<int> items() const {
is_item_bad iib = { &bad_items; };
std::vector<int> good_items(all_items.size());
std::remove_copy_if(all_items.begin(), all_items.end(),
good_items.begin(), is_item_bad);
return good_items;
}
Assume all_items, bad_items, is_item_bad and items() are all a part of some containing class. Is there a way to write them items() getter such that:
It doesn't need temporary variables in the method?
It doesn't need the custom functor, struct is_item_bad?
I had hoped to just use the count method on std::set as a functor, but I haven't been able to divine the right way to express that w/ the remove_copy_if algorithm.
EDIT: Fixed the logic error in items(). The actual code didn't have the problem, it was a transcription error.
EDIT: I have accepted a solution that doesn't use std::set_difference since it is more general and will work even if the std::vector isn't sorted. I chose to use the C++0x lambda expression syntax in my code. My final items() method looks like this:
std::vector<int> items() const {
std::vector<int> good_items;
good_items.reserve(all_items.size());
std::remove_copy_if(all_items.begin(), all_items.end(),
std::back_inserter(good_items),
[&bad_items] (int const i) {
return bad_items.count(i) == 1;
});
}
On a vector of about 8 million items the above method runs in 3.1s. I bench marked the std::set_difference approach and it ran in approximately 2.1s. Thanks to everyone who supplied great answers.
As jeffamaphone suggested, if you can sort any input vectors, you can use std::set_difference which is efficient and less code:
#include <algorithm>
#include <set>
#include <vector>
std::vector<int>
get_good_items( std::vector<int> const & all_items,
std::set<int> const & bad_items )
{
std::vector<int> good_items;
// Assumes all_items is sorted.
std::set_difference( all_items.begin(),
all_items.end(),
bad_items.begin(),
bad_items.end(),
std::back_inserter( good_items ) );
return good_items;
}
Since your function is going to return a vector, you will have to make a new vector (i.e. copy elements) in any case. In which case, std::remove_copy_if is fine, but you should use it correctly:
#include <iostream>
#include <vector>
#include <set>
#include <iterator>
#include <algorithm>
#include <functional>
std::vector<int> filter(const std::vector<int>& all, const std::set<int>& bad)
{
std::vector<int> result;
remove_copy_if(all.begin(), all.end(), back_inserter(result),
[&bad](int i){return bad.count(i)==1;});
return result;
}
int main()
{
std::vector<int> all_items = {4,5,2,3,4,8,7,56,4,2,2,2,3};
std::set<int> bad_items = {2,8,4};
std::vector<int> filtered_items = filter(all_items, bad_items);
copy(filtered_items.begin(), filtered_items.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
}
To do this in C++98, I guess you could use mem_fun_ref and bind1st to turn set::count into a functor in-line, but there are issues with that (which resulted in deprecation of bind1st in C++0x) which means depending on your compiler, you might end up using std::tr1::bind anyway:
remove_copy_if(all.begin(), all.end(), back_inserter(result),
bind(&std::set<int>::count, bad, std::tr1::placeholders::_1)); // or std::placeholders in C++0x
and in any case, an explicit function object would be more readable, I think:
struct IsMemberOf {
const std::set<int>& bad;
IsMemberOf(const std::set<int>& b) : bad(b) {}
bool operator()(int i) const { return bad.count(i)==1;}
};
std::vector<int> filter(const std::vector<int>& all, const std::set<int>& bad)
{
std::vector<int> result;
remove_copy_if(all.begin(), all.end(), back_inserter(result), IsMemberOf(bad));
return result;
}
At the risk of appearing archaic:
std::set<int> badItems;
std::vector<int> items;
std::vector<int> goodItems;
for ( std::vector<int>::iterator iter = items.begin();
iter != items.end();
++iter)
{
int& item = *iter;
if ( badItems.find(item) == badItems.end() )
{
goodItems.push_back(item);
}
}
std::remove_copy_if returns an iterator to the target collection. In this case, it would return good_items.end() (or something similar). good_items goes out of scope at the end of the method, so this would cause some memory errors. You should return good_items or pass in a new vector<int> by reference and then clear, resize, and populate it. This would get rid of the temporary variable.
I believe you have to define the custom functor because the method depends on the object bad_items which you couldn't specify without it getting hackey AFAIK.