What is the problem with this code:
#include <iostream>
#include <vector>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/any_range.hpp>
using namespace boost::adaptors;
using Range =
boost::any_range<
int,
boost::forward_traversal_tag,
int,
std::ptrdiff_t>;
void magic(const Range &) {}
int main()
{
std::vector<int> xs{0, 1, 2};
auto ys = xs | transformed([](auto x) { return x; });
const Range zs = ys;
std::vector<int> us{boost::begin(zs), boost::end(zs)};
magic(us);
return 0;
}
Complie:
c++ -g -std=c++14 -O2 main.cpp
Run and get segfault.
But when I compile with lower optimization level, then everything is ok.
gdb output:
Program received signal SIGSEGV, Segmentation fault.
0x00000000004011a5 in boost::range_detail::any_iterator<int, boost::iterators::forward_traversal_tag, int, long, boost::any_iterator_buffer<64ul> >::dereference (this=<optimized out>) at /usr/include/boost/range/detail/any_iterator.hpp:512
512 return m_impl->dereference();
Is this boost::any_range bug, or I misuse the library?
Program also crashes if I compile it this way:
c++ -g -std=c++14 -O1 -fisolate-erroneous-paths-dereference main.cpp
The program below crashes too, if I compile it with options -O1 -fisolate-erroneous-paths-dereference:
#include <iostream>
#include <vector>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/any_range.hpp>
using namespace boost::adaptors;
using Range =
boost::any_range<
int,
boost::forward_traversal_tag,
int &,
std::ptrdiff_t>;
void magic(const Range &xs) {
for (auto x: xs) { std::cout << xs; }
}
int main()
{
std::vector<int> xs{0, 1, 2};
auto ys = xs | transformed([](auto x) { return x; });
magic(ys);
return 0;
}
This is boost bug 10493, related to 10360, which was introduced in 1.56 (2014-08) and was only finally fixed in 1.74 (2020-08) via fix PR #94
Until 1.74, the problem is that instead of just using your reference type, it wraps it in mutable_reference_type_generator, which prevents you from being able to return a temporary. That is, when you write:
using Range =
boost::any_range<
int,
boost::forward_traversal_tag,
int,
std::ptrdiff_t>;
You're explicitly specifying your reference type to be int, not int&, because your range is basically an input range. But the boost internals are changing it to int& anyway, so you dangle. When you write const int intsead of int, the type trait doesn't add the reference, so you actually do end up with const int.
Actually when I was typing the title for my question, this question was offered as possible answer.
As suggested in the answer for the question, I replaced int with const int and it worked:
using Range =
boost::any_range<
int,
boost::forward_traversal_tag,
const int,
std::ptrdiff_t>;
I decided to publish the question because the quoted question is not marked as answered.
Related
I was trying to remove some redundant code from one of my personal projects and got an idea to dynamically create some properties, so the code is the following
#include <functional>
#include <string>
#include <variant>
struct t {
void i(int) {}
void s(std::string) {}
void b(bool) {}
};
int main() {
using setters = std::variant<std::function<void(t *, int)>,
std::function<void(t *, std::string)>,
std::function<void(t *, bool)>>;
std::initializer_list<std::pair<const char *, setters>> props{
{"first", std::function<void(t*, int)>(&t::i)}, {"second", &t::i}};
int i = 0;
for(auto& p : props) {
if (std::get<std::function<void(t*, int)>>(p.second))
i += 2;
}
return i;
}
this actually fails to compile but if I replace &t::i with &t::s for second it actually compiles fine and also if I implicitly specify the type of second it compiles fine also, but I don't like to specify types everywhere, so is there any way to fix it and also it will not compile if I remove the type of first, so is there any way to remove the type specification of first as well
Here is the godbolt link if anyone wants
https://godbolt.org/z/GSb8CL
I guess this is the first time I couldn't manage to find an already answered question in here, and I could really use some help if anyone have successfully used boost coroutine2 lib without lambdas.
My problem, sumarized:
class worker {
...
void import_data(boost::coroutines2::coroutine
<boost::variant<long, long long, double, std::string> >::push_type& sink) {
...
sink(stol(fieldbuffer));
...
sink(stod(fieldbuffer));
...
sink(fieldbuffer); //Fieldbuffer is a std::string
}
};
I intend to use this as a coroutine from inside another class, that has the task of putting each yielded value in its place, so I tried to instantiate an object:
worker _data_loader;
boost::coroutines2::coroutine<boost::variant<long, long long, double, string>>::pull_type _fieldloader
(boost::bind(&worker::import_data, &_data_loader));
but that wont compile:
/usr/include/boost/bind/mem_fn.hpp:342:23:
error: invalid use of non-static member function of type
‘void (worker::)(boost::coroutines2::detail::push_coroutine<boost::variant<long int, long long int, double, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&)’
Could someone shed any light in this problem?
This has nothing to do with Boost Coroutine.
It is just about bind with a member function. You forgot to expose the unbound parameter:
boost::bind(&worker::import_data, &_data_loader, _1)
Live On Coliru
#include <boost/coroutine2/all.hpp>
#include <boost/variant.hpp>
#include <boost/bind.hpp>
#include <string>
using V = boost::variant<long, long long, double, std::string>;
using Coro = boost::coroutines2::coroutine<V>;
class worker {
public:
void import_data(Coro::push_type &sink) {
sink(stol(fieldbuffer));
sink(stod(fieldbuffer));
sink(fieldbuffer); // Fieldbuffer is a std::string
}
std::string fieldbuffer = "+042.42";
};
#include <iostream>
int main()
{
worker _data_loader;
Coro::pull_type _fieldloader(boost::bind(&worker::import_data, &_data_loader, _1));
while (_fieldloader) {
std::cout << _fieldloader.get() << "\n";
_fieldloader();
}
}
Prints
42
42.42
+042.42
I have the following piece of code that seems to work fine (I based the semantic actions on reuse parsed variable with boost karma).
#include <iostream>
#include <iterator>
#include <memory>
#include <string>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/sequence.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/include/support_attributes.hpp>
#include <boost/spirit/include/support_adapt_adt_attributes.hpp>
using namespace boost::spirit;
struct DataElement
{
DataElement(const std::string& s) : str_(s) {}
const std::string& str() const { return str_; }
std::string& str() { return str_; }
std::string str_;
};
using Data = std::vector<std::shared_ptr<const DataElement>>;
namespace boost {
namespace spirit {
namespace traits {
template<>
struct transform_attribute<std::shared_ptr<const DataElement> const, const DataElement&, karma::domain>
{
using type = const DataElement&;
static type pre(const std::shared_ptr<const DataElement>& val) { return *val; }
};
}
}
}
BOOST_FUSION_ADAPT_ADT(
DataElement,
(std::string&, const std::string&, obj.str(), obj.str())
);
template<typename Iterator>
struct TheGrammar: public karma::grammar<Iterator, Data()>
{
TheGrammar(): karma::grammar<Iterator, Data()>(start)
{
start %= -(elt % karma::eol);
elt %=
karma::lit("'some prefix'")
<< karma::string [karma::_1 = boost::phoenix::at_c<0>(karma::_val)]
<< karma::lit("'some infix 1'")
<< karma::string [karma::_1 = boost::phoenix::at_c<0>(karma::_val)]
<< karma::lit("'some infix 2'")
<< karma::string [karma::_1 = boost::phoenix::at_c<0>(karma::_val)]
<< karma::lit("'some suffix'")
;
}
karma::rule<Iterator, Data()> start;
karma::rule<Iterator, const DataElement&()> elt;
};
int main(void)
{
Data vec = {
std::make_shared<DataElement>("one"),
std::make_shared<DataElement>("two"),
std::make_shared<DataElement>("three"),
std::make_shared<DataElement>("four"),
std::make_shared<DataElement>("five"),
std::make_shared<DataElement>("six"),
std::make_shared<DataElement>("seven"),
std::make_shared<DataElement>("eight"),
};
using iterator_type = std::ostream_iterator<char>;
iterator_type out(std::cout);
TheGrammar<iterator_type> grammar;
return karma::generate(out, grammar, vec);
}
I would like to understand a couple of things:
Why don't I need to use karma::attr_cast anywhere? My start rule is a vector of std::shared_ptr whereas the elt rule works on the actual object const reference. I originally tried attr_cast but got nowhere, and sort of tried this version only halfheartedly just in case it worked, and it worked...
Why does it still compile if I comment out my custom transform_attribute altogether? Is there some default std::shared_ptr<T> -> T& transform_attribute provided? I couldn't find much, but maybe I'm not looking int the right place?
If I comment out my custom transform_attribute, as mentioned above, the code still compiled, but there's clearly some memory corruption at runtime. The karma::string generate garbage. In a way, I can understand that something funny must be happening since I don't even tell karma how to get from my shared_ptr to the objects. Is the fact that it compiles the actual error/bug?
Thanks a lot for your time and help!
each rule has an implicit attr_cast to the declared attribute type
Somehwere along the way Spirit's type compatibility rules go haywire. All I've seen is it has to do with the fact that the string type is a container. Somewhere along the way it "copy-constructs" a std::string that appears to have length 97332352. Unsurprisingly that is itself wrong and happens to trigger UB because the ranges that end up being passed to memset overlap:
Source and destination overlap in memcpy(0x60c1040, 0x5cd2c90, 97332352)
at 0x4C30573: memcpy##GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x401B26: copy (char_traits.h:290)
by 0x401B26: _S_copy (basic_string.h:299)
by 0x401B26: _S_copy_chars (basic_string.h:342)
by 0x401B26: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) [clone .isra.53] (basic_string.tcc:229)
by 0x402442: _M_construct_aux<char*> (basic_string.h:195)
by 0x402442: _M_construct<char*> (basic_string.h:214)
by 0x402442: basic_string (basic_string.h:401)
by 0x402442: call<const boost::spirit::unused_type> (extract_from.hpp:172)
by 0x402442: call<const boost::spirit::unused_type> (extract_from.hpp:184)
by 0x402442: extract_from<std::__cxx11::basic_string<char>, boost::fusion::extension::adt_attribute_proxy<DataElement, 0, true>, const boost::spirit::unused_type> (extract_from.hpp:217)
by 0x402442: extract_from<std::__cxx11::basic_string<char>, boost::fusion::extension::adt_attribute_proxy<DataElement, 0, true>, const boost::spirit::unused_type> (extract_from.hpp:237)
by 0x402442: pre (attributes.hpp:23)
Yes, that's a QoI issue.
The problem often is with c++'s implicit conversions. Pointer types have many unexpected conversions. Shared pointers do have their contextual conversion to bool.
More notes:
Your fusion adaptation seemed flawed: val was not being used in the setter
BOOST_FUSION_ADAPT_ADT(DataElement, (std::string &, const std::string &, obj.str(), obj.str() = val))
You're doing many things I've learned to avoid.
I prefer to have semantic-action-less rules: Boost Spirit: "Semantic actions are evil"?
I don't do shared-pointers in Spirit grammars/generators How can I use polymorphic attributes with boost::spirit::qi parsers? (arguably, in a generator setting it's less of a problem!)
I don't do ADT adaptation (it's too easy to get bitten with UB) Error when adapting a class with BOOST_FUSION_ADAPT_ADT
I try to use boost::bind with std::vector<>::resize.
But the following code won't compile:
#include <boost/bind.hpp>
#include <vector>
using namespace boost;
int main(){
typedef std::vector<double> type;
type a;
bind(&type::resize, _1, 2)(a);
return 0;
}
So, how can I do this?
Thanks!
boost version 1.53
gcc version 4.8 or 4.6
*Edit: * The above code works with -std=c++11. In fact, my original problem is this:
#include <boost/bind.hpp>
#include <blitz/array.h>
#include <vector>
using namespace boost;
using namespace blitz;
int main(){
typedef Array<double, 1> type;
type a;
//a.resize(4) is ok;
bind(&type::resize, _1, 2)(a);
return 0;
}
My compile command is:
g++ t.cpp -I path/include/ -std=c++11 -L path/lib/ -l blitz
resize might be an overloaded function (in C++11 it has to be) so you need to tell the compiler which overload you want. For the one argument form, this should work in C++11:
bind(static_cast<void (type::*)(type::size_type)>(&type::resize), _1, 2)(a);
Or more readably:
typedef void (type::*resize_signature)(type::size_type);
bind(static_cast<resize_signature>(&type::resize), _1, 2)(a);
If it's not an overloaded function (as with GCC in C++03 mode) then it takes two arguments (one has a default value) and you need to supply the second argument because bind can't use default arguments:
typedef void (type::*resize_signature)(type::size_type, const value_type&);
bind(static_cast<resize_signature>(&type::resize), _1, 2, 0.0)(a);
Unfortunately this C++03 version isn't portable, implementations are allowed to use a single function or a pair of overloads. To make it portable, or to work with other types such as Array you can wrap the call in a custom functor that calls resize, so you don't need to know the exact signature:
typename<class VecT>
struct resizer<VecT> {
void operator()(VecT& v, unsigned n) const { v.resize(n); }
};
// ...
bind(resizer<type>(), _1, 2)(a);
Or in C++11 just use a lambda expression instead of bind:
auto resize = [](type& v) { v.resize(2); };
resize(a);
The following header works with the commented part as expected when I call the function bat with no arguments:
class Test
{
public:
void bat(std::vector<int> k = std::vector<int>()) {}
//void cat(std::map<int, std::vector<int> > k = std::map<int, std::vector<int> >()) {}
};
But when I try using the cat function in the header:
class Test
{
public:
void bat(std::vector<int> k = std::vector<int>()) {}
void cat(std::map<int, std::vector<int> > k = std::map<int, std::vector<int> >()) {}
};
I get:
test.h:14: error: expected ',' or '...' before '>' token
test.h:14: error: wrong number of template arguments (1, should be 4)
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_map.h:92: error: provided for 'template<class _Key, class _Tp, class _Compare,\
class _Alloc> class std::map'
test.h:14: error: default argument missing for parameter 2 of 'void Test::cat(std::map<int, std::vector<int, std::allocator<int> >, std::less<int>, std::all\
ocator<std::pair<const int, std::vector<int, std::allocator<int> > > > >, std::vector<int, std::allocator<int> >)'
How come? And are there easy workarounds for this? hopefully not requiring a pointer type change in the interface?
This is my full header:
#ifndef TEST_H
#define TEST_H
#include <map>
#include <vector>
#include <sstream>
#include <iostream>
class Test
{
public:
//void bat(std::vector<int> k = std::vector<int>()) {}
void cat(std::map<int, std::vector<int> > k = std::map<int, std::vector<int> >()) {}
};
#endif
so all the right includes are there. My version of GCC is terribly outdated (well not at home, ill try it at home too) - but at work it's 4.1.2
The code looks OK, but fails on gcc 4.3.4, see here, but compiles fine with 4.6 onwards (I haven't tested 4.4 or 4.5). So it looks like the workaround is to use a newer gcc.
#include <map>
#include <vector>
class Test
{
public:
void bat(std::vector<int> k = std::vector<int>()) {}
void cat(std::map<int, std::vector<int> > k = std::map<int, std::vector<int> >
()) {}
};
int main() {
}
Concerning default parameters, it may be an idea to drop them altogether:
class Test {
public:
void bat(std::vector<int> k) {}
void bat() {}
void cat(std::map<int, std::vector<int> > k) {}
void cat() {}
};
otherwise, you couple the default parameters to the interface, meaning you cannot change them without requiring re-compilation of all client code.
The code you've posted seems fine, so I'm going to turn on my Psychic Debugger module.
Did you:
#include <vector>
...in your header?
From the other posts here, it looks like it could be a compiler problem, in which case, you can get around it by using a typedef instead of the map type directly.
#include <vector>
#include <map>
class Test
{
public:
typedef std::map<int, std::vector<int> > MyMap;
void bat(std::vector<int> k = std::vector<int>()) {}
void cat(MyMap k = MyMap()) {}
};
int main()
{
}
This is C++ core Defect Report 325 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#325
GCC 4.4 implements the suggested (but not yet official) resolution of the DR, see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57#c36