Are boost::bind and boost::function compatible with SEH? - c++

I have a function that uses boost::bind to move function evaluation into a try/catch wrapper, based on this question.
Problem is, boost::bind doesn't seem to work with SEH - and worse, it returns a garbage value, which is exactly what I don't want. Have I made a botch of it somewhere? Even stranger, the switch /EHsc or /EHa doesn't actually seem to matter to the behavior of the program. The output you get is:
Calling
-2147483648
Done.
Press any key to continue . . .
How do I even start to figure out where things have gone wrong?
#pragma once
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <windows.h>
#include <eh.h>
using boost::function;
using boost::bind;
int potato(int q)
{
double r = 0;
return q / r;
}
template<typename T>
T exception_wrapper(boost::function<T()> func)
{
try
{
std::cout << "Calling" << std::endl;
return func();
std::cout << "After Call" << std::endl;
}
catch (...) {
std::cout << "Ex Caught" << std::endl;
return 45;
}
}
void trans_func(unsigned int u, EXCEPTION_POINTERS* pExp)
{
throw std::runtime_error("huh");
}
int main()
{
int result = exception_wrapper<int>(bind(potato, 123));
std::cout << result << std::endl;
std::cout << "Done." << std::endl;
}

Related

When using variant but error-invoke, could errors happens in compiling time instead of bad_variant_access in running time

If I have a map like
const std::map<int, std::variant<int, std::string>> m ={{1,1},{2,"asd"}};
But if i invoke std::get<string>(m[1]) by mistake instead of std::get<int>(m[1]), it will raise bad_variant_access.
But it is just a typo of codes, so could it be detected by IDE, or some form of static_assert could work because m is a constant(or what if m is not a constant) , or raise only compile errors?
If it is always constant, you don't need a map. You can dispatch that at compile time:
#include <iostream>
template <int i>
constexpr auto m()
{
if constexpr (i == 1) {
return 1;
} else if constexpr (i == 2) {
return "hello";
}
}
int main()
{
std::cout << m<1>() << '\n';
std::cout << m<2>() << '\n';
}
Or, just use a tuple:
#include <iostream>
#include <tuple>
int main()
{
std::tuple tuple { 1, "hello world" };
std::cout << std::get<0>(tuple) << '\n';
std::cout << std::get<1>(tuple) << '\n';
}

How can a simple std::cout << "---" << std::endl; alter how UB manifests?

Some background
Today I saw, in the body of a function kaboom, a local shared_ptr pointing to a *global object and, being captured by reference and its pointee returned by reference by a lambda, i.e. [&local]() -> auto& { return *local; }; this lambda was stored somehow for further use after the function kaboom returned.
As soon as I saw this, I thought the code was invoking undefined behavior. I tried to make a minimal example to support my claim, and came up with the following.
#include <iostream>
#include <memory>
#include <functional>
#include <vector>
struct Resource {
const int i{3};
};
std::shared_ptr<Resource> global = std::make_unique<Resource>();
auto getSharedStuff() {
return global;
}
std::vector<std::function<Resource&()>> actions{};
void kaboom() {
std::shared_ptr<Resource> local = getSharedStuff();
actions.push_back([&local]() -> auto& { return *local; });
}
int main() {
kaboom();
std::cout << global->i << std::endl;
std::cout << actions[0]().i << std::endl;
}
The simple fact that the 2 couts give 3 and 0 respectively is proof for me that I'm observing UB (3 is correct, and 0 could have been anything, including 3, but I've been lucky that it was not 3, so the UB is well manifest).
Good.
The code I'm curious about
But before getting there, an intermediate version of the repro above was this:
#include <iostream>
#include <memory>
#include <functional>
#include <vector>
struct Resource {
Resource(Resource const&) = delete;
Resource(Resource&&) = delete;
Resource() { std::cout << this << "'s ctor" << std::endl; }
~Resource() { std::cout << this << "'s dtor" << std::endl; }
void operator()() { std::cout << this << "'s operator()" << std::endl; }
};
std::shared_ptr<Resource> global = std::make_unique<Resource>();
auto getSharedStuff() {
return global;
}
std::vector<std::function<Resource&()>> actions{};
void kaboom() {
std::shared_ptr<Resource> local = getSharedStuff();
actions.push_back([&local]() -> auto& { return *local; });
}
int main() {
kaboom();
std::cout << "---" << std::endl;
actions[0]()();
}
which can result in this output
0xc602b0's ctor
---
0x7f0f48f7f4a0's operator()
0xc602b0's dtor
I'm kind of ok with this, as actions[0]()() is dereferencing a destroyed shared_ptr and calling operator() on the screwed up result, so I accept that this can be screwup too.
What's funny, though, is that removing std::cout << "---" << std::endl; makes UB less manifest, as the output becomes something like this:
0xce92b0's ctor
0xce92b0's operator()
0xce92b0's dtor
So my question is: how can a "simple" line as std::cout << "---" << std::endl; affect this way the manifestation of UB?

Something really weird with C++ exp() function

When tying to implement mySqrt function in C++, I used the exp() function like this:
int mySqrt(int x) {
// For x = 2147395600
cout << exp(0.5*log(x)) << " "; // It prints 46340
return exp(0.5*log(x)); // But returns 46339
}
I tried to google the reason for this behavior but could not find anything. I even tried using double but still the same output.
Any explanation for this?
With this code
#include <iostream>
#include <cmath>
#include <cstdio>
using std::cout;
int mySqrt(int x) {
// For x = 2147395600
cout << exp(0.5*log(x)) << " "; // It prints 46340
return exp(0.5*log(x)); // But returns 46349
}
int main(void) {
std::cout << mySqrt(2147395600) << "\n";
printf("%.30f\n", exp(0.5*log(2147395600)));
return 0;
}
I got output:
46340 46339
46339.999999999978172127157449722290
It seems the value is rounded when passed to cout while truncated when converted to int.

Concurrent cout formatting

This is an academic question.
sdt::mutex m;
typedef std::lock_guard<std::mutex> G;
void thread1(){
G g(m);
std::cout << std::setw(9);
std::cout << 3.14;
std::cout << std::endl;
}
void thread2(){
G g(m);
std::cout << std::setw(7);
std::cout << 3.14;
std::cout << std::endl;
}
My problem is that the formatting is bound to the output stream, so I need to set all the formatting options ever invented on my thread if I want to be sure about the output I produce. Which will or will not work next year.
Is there any way to reset formatting to default without setting everything by hand?
If not, what are the good workarounds?
For example should I create and keep an std::ostringstream locally on my thread and write oss.str() to std::cout?
I've used boost for brevity but you could write your own optional and state saver.
#include <mutex>
#include <iostream>
#include <iomanip>
#include <tuple>
#include <utility>
#include <boost/io/ios_state.hpp>
#include <boost/optional.hpp>
std::mutex m;
struct save_and_lock
{
boost::optional<boost::io::ios_all_saver> saver;
std::unique_lock<std::mutex> lock;
void init(std::ostream& os)
{
lock = std::unique_lock<std::mutex>(m);
saver.emplace(os);
os.flags(std::ios_base::fmtflags(0));
}
friend std::ostream& operator<<(std::ostream& os, save_and_lock&& s)
{
s.init(os);
return os;
}
};
void thread1(){
std::cout << save_and_lock() << std::setw(9) << 3.14 << std::endl;
}
void thread2(){
std::cout << save_and_lock() << std::setw(9) << 3.14 << std::endl;
}
This will work because the evaluation order of user-defined operator << is left to right.

My function does not modify its inputs

I'm trying to learn C++ and have this small beginner question:
why does the standardize function not modify its inputs?
To help with the answers, I have posted an executing code at Coliru
here
and the sources of my program below.
Referring to the code, the question would be: why isn't what's
printed after outside the same as what's printed after inside?
#include <cstdlib>
#include <ctime>
#include <algorithm> // std::copy
#include <iostream>
using namespace std;
void standardize(const int n,const float x[],float ave,float sct){
float acc=0.0f,sum=0.0f;
sum=std::accumulate(x,x+n,0.0f);
ave=sum/(float)n;
std::for_each(x,x+n,[&](const float d){acc+=(d-ave)*(d-ave);});
sct=std::sqrt(acc/(float)(n-1));
std::cout << "inside" << std::endl;
std::cout << ave << std::endl;
std::cout << sct << std::endl;
return;
}
int main(){
const int n=1024;
float a2[n];
float part0=0.0f,part1=0.0f;
std::srand(std::time(0));
for(int i=0;i<n;i++) a2[i]=std::rand()/(float)RAND_MAX;
standardize(n,a2,part0,part1);
std::cout << "outside" << std::endl;
std::cout << part0 << std::endl;
std::cout << part1 << std::endl;
}
You are passing ave and sct by values. Your standardize method modifies copies of those arguments, letting unchanged the original ones declared in main()
Consider passing them by reference:
void standardize(const int n,const float x[],float& ave,float& sct)