I've written a convenient functor wrapper for tuple std::get. When using it with boost transformed and operator[], I get warning that I'm returning reference to local temporary object. My system: ubuntu 14.04, compilers: clang-3.5 and g++-4.8.2, boost version: 1.56.
#include <boost/range/adaptor/transformed.hpp>
#include <utility>
#include <vector>
template <std::size_t I>
struct tuple_get {
template <typename Tuple>
auto operator()(Tuple &&tuple) const ->
decltype(std::get<I>(std::forward<Tuple>(tuple))) {
return std::get<I>(std::forward<Tuple>(tuple));
}
};
int main() {
//removing const gets rid of warning
const std::vector<std::tuple<int,int>> v = {std::make_tuple(0, 0)};
//gives warning
(v | boost::adaptors::transformed(tuple_get<0>{})) [0];
}
Warning details:
include/boost/range/iterator_range_core.hpp:390:16: warning: returning reference to local temporary object [-Wreturn-stack-address]
return this->m_Begin[at];
note: in instantiation of member function 'boost::iterator_range_detail::iterator_range_base<boost::transform_iterator<tuple_get<0>,
std::__1::__wrap_iter<const std::__1::tuple<int, int> *>, boost::use_default, boost::use_default>, boost::random_access_traversal_tag>::operator[]' requested here
(v | boost::adaptors::transformed(tuple_get<0>{})) [0];
Adding flag -Wreturn-stack-address is not a solution since it's dangerous in bigger projects.
I noticed that deleting const keyword gets rid of warning but I don't know why and don't want to assume that functor gets only non-const ranges.
Questions: how to fix code to get rid of warning? Why deleting const gets rid of warning?
It's true.
//
// When storing transform iterators, operator[]()
// fails because it returns by reference. Therefore
// operator()() is provided for these cases.
//
So, you should be able to fix it with
(v | boost::adaptors::transformed(tuple_get<0>{})) (0);
which returns the abstract_value_type (which is the reference only if the elements are abstract, array or function, the value_type otherwise).
Related
I have some code like these (from cppcon), when inserting a non-const pair into a unordered_map, the performance is very different to inserting with a const one.
#include <algorithm>
#include <chrono>
#include <iostream>
#include <iterator>
#include <unordered_map>
#include <vector>
using namespace std;
struct StopWatch {
StopWatch() : clk{std::chrono::system_clock::now()} {}
~StopWatch() {
auto now = std::chrono::system_clock::now();
auto diff = now - clk;
cout << chrono::duration_cast<chrono::microseconds>(diff).count() << "ms"
<< endl;
}
decltype(std::chrono::system_clock::now()) clk;
};
void Benchmark_Slow(int iters) {
std::unordered_map<string, int> m;
std::pair<const string, int> p = {};
while (iters--)
m.insert(p);
}
void Benchmark_Fast(int iters) {
std::unordered_map<string, int> m;
const std::pair<const string, int> p = {};
while (iters--)
m.insert(p);
}
int main(void) {
{
StopWatch sw;
Benchmark_Fast(1000000);
}
{
StopWatch sw;
Benchmark_Slow(1000000);
}
return 0;
}
A online demo: Compiler Explorer
128247ms
392454ms
It seems that the const qualifier let the compiler to choose the unordered_map::insert(const value_type&) overload instead of the unordered_map::insert( P&& value ).
cppreference: unordered_map::insert
But I think that a forwarding templated universal reference insert(P&& value) would be the same as an insert with const lvalue reference, an identical copy operation.
But the emplace one(with non-const pair) runs much slower than insert one(with const pair).
Am I missing something here ? Or if this is something has a keyword to be searched on the google, I didn't find something answers that. Thank you in advance.
I think I do found a possible explanation.
from emplace it describe that if insertion fails, the constructed element would be destroyed immediately.
I follow the assembly code compiled with libstd++ of unordered_map::emplace (which accept templated argument and do std::forward) and unordered_map::insert link provided by #Jarod42, I the emplace one always allocate a new hash_node before it check if the key already in the map, because it's templated and it didn't know the argument type (maybe it only know it's is_convertible_to), so it do the construction before examine the key. The one in libc++ seems recognize the type is a const reference thus do the same as the insert one, copy construct occurs only if the key is not exsist.
When I modified the code with different key to be inserted, the difference gone away. quick C++ benchmark
I don't know did I miss something else. I' m sorry for this trivial problem was posted.
What am I missing here? Why can't I use decltype to define the value_type of an iterator? The code below gets inscrutable compile-time errors when I use decltype rather than iterator_traits, but only if I also use value_type to declare a vector.
Visual Studio 2017, C++17 rev. 15.6 Preview
#include <vector>
template<class Ptr >
void foo(Ptr beg) {
*beg = 1; // Cool, babies.
// using value_type = decltype(*beg); // COMPILER ERROR when buf declared below
using value_type = typename std::iterator_traits<Ptr>::value_type;
std::vector<value_type> buf(1); // Remove this and decltype compiles.
}
int main() {
std::vector<int> bar(1);
foo(std::begin(bar));
*(std::begin(bar)) = 1;
return 0;
}
By request...
error C2528: 'const_pointer': pointer to reference is illegal
It's for the same reason when you have:
void foo(int *beg)
then
decltype(*beg)
Does not give you an int. You get an int & here. That's what, essentially, your using declaration ends up getting: a reference, an uninvited hitch-hiker.
If you insist on using decltype, you can do:
using value_type = typename std::remove_reference<decltype(*beg)>::type;
In order to ditch the unwelcome hitch-hiker.
I'm observing a rather weird behaviour of the following piece of code:
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/any_range.hpp>
#include <vector>
#include <string>
#include <iostream>
#include "gsl.h"
template <typename T>
using ImmutableValueRange = boost::any_range<T, boost::bidirectional_traversal_tag, /*const*/ T>;
template <typename T, typename C>
ImmutableValueRange<T> make_transforming_immutable_range(const C& container)
{
return container | boost::adaptors::transformed([](const typename C::value_type& v) -> T
{
//std::cout << "trans : " << T{ v }.data() << "\n";
return T{ v };
});
}
void f(ImmutableValueRange<gsl::cstring_span<>> r)
{
for (const auto& c : r) {
std::cout << c.data() << "\n";
}
}
int main()
{
std::vector<std::string> v({ "x", "y", "z" });
f(make_transforming_immutable_range<gsl::cstring_span<>>(v));
}
The idea here is to isolate the actual representation of a sequence of strings that is received as a parameter by the function f behind an any_range and gsl::string_span (note, the commit changing string_view to string_span has been made a couple of hours ago to GSL).
My original code did not have a const T as Reference template parameter to any_range (it was a simple T) and it crashed during execution. However, that happened only in Release mode an worked fine in Debug or RelWithDebInfo (generated by CMake). I used VS2013/2015 x64. Furthermore, trying to debug the full Release version, adding debug output to the conversion lambda eliminated the crash (my guess is it prevented some inlining). My final working solution is to specify const T as Reference.
However, I'm still wondering why did the crash happen in the first place? Is it the VS compiler bug? Bug in the current implementation of string_span? Or am I simply misusing the boost::any_range?
Edit
Just built the version with clang 3.7.0 and the behaviour is similar (works fine in debug and doesn't crash, but outputs garbage without const T with -O2). So it doesn't seem like a compiler problem.
As it turns out, the any_range's dereference method will return a reference to T unless the Reference type is specified as const T, thus creating a dangling reference to a temporary. This happens due to use of any_incrementable_iterator_interface::mutable_reference_type_generator defined in any_iterator_interface.hpp.
Therefore, the correct solution to the problem is indeed to specify const T as the Reference type in case the iterator dereferencing returns a temporary.
This is a bug in boost::range and a fix was only merged in Feb of 2020, but didn't make it into 1.73. The fix is available as of 1.74
https://github.com/boostorg/range/pull/94
After a quick look, I suspect the problem lies in your lambda. If I understood correctly, you end up taking a std::string by const reference with the following parameter declaration:
const typename C::value_type& v
However, you are then using v to construct a cstring_span. Here's the rub: cstring_span only has a constructor that goes from a non-const reference to a container type (like std::string). Conceptually, the constructor looks like this:
template <class Cont>
cstring_span(Cont& c)
So I am guessing that when you return from your lambda, a temporary is being created from v, and then passed to the cstring_span constructor in order to provide a non-const reference argument. Of course, once that temporary gets cleaned up, your cstring_span is left dangling.
I am trying to initialise an std::vector<std::unique_ptr<std::string>> in a way that is equivalent to an example from Bjarne Stroustrup's C++11 FAQ:
using namespace std;
vector<unique_ptr<string>> vs { new string{"Doug"}, new string{"Adams"} }; // fails
unique_ptr<string> ps { new string{"42"} }; // OK
I can see no reason why this syntax should fail. Is there something wrong with this way of initializing the container?
The compiler error message is huge; the relevant segment I find is below:
/usr/lib/gcc-snapshot/lib/gcc/i686-linux-gnu/4.7.0/../../../../include/c++/4.7.0
/bits/stl_construct.h:77:7: error: no matching function for call to
'std::unique_ptr<std::basic_string<char> >::unique_ptr(std::basic_string<char>&)'
What is the way to fix this error ?
unique_ptr's constructor is explicit. So you can't create one implicitly with from new string{"foo"}. It needs to be something like unique_ptr<string>{ new string{"foo"} }.
Which leads us to this
// not good
vector<unique_ptr<string>> vs {
unique_ptr<string>{ new string{"Doug"} },
unique_ptr<string>{ new string{"Adams"} }
};
However it may leak if one of the constructors fails. It's safer to use make_unique:
// does not work
vector<unique_ptr<string>> vs {
make_unique<string>("Doug"),
make_unique<string>("Adams")
};
But... initializer_lists always perform copies, and unique_ptrs are not copyable. This is something really annoying about initializer lists. You can hack around it, or fallback to initialization with calls to emplace_back.
If you're actually managing strings with smart pointers and it's not just for the example, then you can do even better: just make a vector<string>. The std::string already handles the resources it uses.
After "fixing" your example:
#include <vector>
#include <memory>
#include <string>
int main()
{
std::vector<std::unique_ptr<std::string>> vs = { { new std::string{"Doug"} }, { new std::string{"Adams"} } }; // fails
std::unique_ptr<std::string> ps { new std::string{"42"} }; // OK
}
I got very a clear error message:
error: converting to 'std::unique_ptr<std::basic_string<char> >' from initializer list would use explicit constructor 'std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>::pointer) [with _Tp = std::basic_string<char>, _Dp = std::default_delete<std::basic_string<char> >, std::unique_ptr<_Tp, _Dp>::pointer = std::basic_string<char>*]'
This error tells us that it is not possible to use the unique_ptr's explicit contructor!
This question now has a better answer, at least in C++17 (C++11 will require a bit more effort). Since this is the first google result when I look for "initializing a vector of unique_ptr", I figured it's worth updating with a solution. Instead of using an initializer list, you can use a variadic function. It's an 8-line gnarly little utility function that looks like this:
#include<memory>
#include<vector>
#include<type_traits>
template <class T> auto move_to_unique(T&& t) {
return std::make_unique<std::remove_reference_t<T>>(std::move(t));
}
template <class V, class ... Args> auto make_vector_unique(Args ... args) {
std::vector<std::unique_ptr<V>> rv;
(rv.push_back(move_to_unique(args)), ...);
return rv;
}
We can now make a vector with an intuitive syntax:
auto vs = make_vector_unique<std::string>(std::string{"Doug"}, std::string{"Adam"});
You can even use it to make a vector of derived class objects.
class B {};
class D : public B {};
auto vb = make_vector_unique<B>(D{}, D{}, D{});
I am trying to initialise an std::vector<std::unique_ptr<std::string>> in a way that is equivalent to an example from Bjarne Stroustrup's C++11 FAQ:
using namespace std;
vector<unique_ptr<string>> vs { new string{"Doug"}, new string{"Adams"} }; // fails
unique_ptr<string> ps { new string{"42"} }; // OK
I can see no reason why this syntax should fail. Is there something wrong with this way of initializing the container?
The compiler error message is huge; the relevant segment I find is below:
/usr/lib/gcc-snapshot/lib/gcc/i686-linux-gnu/4.7.0/../../../../include/c++/4.7.0
/bits/stl_construct.h:77:7: error: no matching function for call to
'std::unique_ptr<std::basic_string<char> >::unique_ptr(std::basic_string<char>&)'
What is the way to fix this error ?
unique_ptr's constructor is explicit. So you can't create one implicitly with from new string{"foo"}. It needs to be something like unique_ptr<string>{ new string{"foo"} }.
Which leads us to this
// not good
vector<unique_ptr<string>> vs {
unique_ptr<string>{ new string{"Doug"} },
unique_ptr<string>{ new string{"Adams"} }
};
However it may leak if one of the constructors fails. It's safer to use make_unique:
// does not work
vector<unique_ptr<string>> vs {
make_unique<string>("Doug"),
make_unique<string>("Adams")
};
But... initializer_lists always perform copies, and unique_ptrs are not copyable. This is something really annoying about initializer lists. You can hack around it, or fallback to initialization with calls to emplace_back.
If you're actually managing strings with smart pointers and it's not just for the example, then you can do even better: just make a vector<string>. The std::string already handles the resources it uses.
After "fixing" your example:
#include <vector>
#include <memory>
#include <string>
int main()
{
std::vector<std::unique_ptr<std::string>> vs = { { new std::string{"Doug"} }, { new std::string{"Adams"} } }; // fails
std::unique_ptr<std::string> ps { new std::string{"42"} }; // OK
}
I got very a clear error message:
error: converting to 'std::unique_ptr<std::basic_string<char> >' from initializer list would use explicit constructor 'std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>::pointer) [with _Tp = std::basic_string<char>, _Dp = std::default_delete<std::basic_string<char> >, std::unique_ptr<_Tp, _Dp>::pointer = std::basic_string<char>*]'
This error tells us that it is not possible to use the unique_ptr's explicit contructor!
This question now has a better answer, at least in C++17 (C++11 will require a bit more effort). Since this is the first google result when I look for "initializing a vector of unique_ptr", I figured it's worth updating with a solution. Instead of using an initializer list, you can use a variadic function. It's an 8-line gnarly little utility function that looks like this:
#include<memory>
#include<vector>
#include<type_traits>
template <class T> auto move_to_unique(T&& t) {
return std::make_unique<std::remove_reference_t<T>>(std::move(t));
}
template <class V, class ... Args> auto make_vector_unique(Args ... args) {
std::vector<std::unique_ptr<V>> rv;
(rv.push_back(move_to_unique(args)), ...);
return rv;
}
We can now make a vector with an intuitive syntax:
auto vs = make_vector_unique<std::string>(std::string{"Doug"}, std::string{"Adam"});
You can even use it to make a vector of derived class objects.
class B {};
class D : public B {};
auto vb = make_vector_unique<B>(D{}, D{}, D{});