I'm having a problem with understanding how boost::factory does its job. The following code will throw in the ctor of test2.
#include <boost/functional/factory.hpp>
#include <boost/function.hpp>
typedef boost::function<A*()> creator;
typedef std::map<string,creator> factory;
class A{
}
class AA : A {
}
class AB : A {
}
class C{
public:
C(factory& f);
factory _f;
}
int main(){
factory f;
f["1"] = boost::factory<AA*>();
f["2"] = boost::factory<AB*>();
C test(f);
C test2(f);
}
C::C(factory& f){
_f = f;
A* t = _f["1"]();
}
The message is
terminate called after throwing an instance of
'boost::exception_detail::clone_impl
' what(): call to empty boost::function
I think I don't understand copy/move behaviour here and that is causing the problem.
As far as I understand, the factory gets copied in C::C, so every call to _f[something]() should get its own function to call. But somehow the function is moved out of the factory in the ctor of test, and then I get a bad function call, cause f["1"] is left in an undefined state.
Please help.
As far as I understand, the factory gets copied in C::C
Yes.
But somehow the function is moved out of the factory in the ctor of test
Nope. If that seems to be the case you likely have Undefined Behaviour elsewhere. Or you might be running a different (buggy) version of boost (this seems highly unlikely).
See if you can reproduce it with the code shown here:
Live On Coliru
#include <boost/functional/factory.hpp>
#include <boost/function.hpp>
#include <map>
#include <iostream>
struct A {};
struct AA : A {
AA() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};
struct AB : A {
AB() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};
typedef boost::function<A*()> creator;
typedef std::map<std::string, creator> factory;
struct C {
C(factory &f){
_f = f;
for (auto& e : _f)
std::cout << "entry for " << e.first << " present " << (!!e.second) << "\n";
}
factory _f;
};
int main() {
factory f;
f["1"] = boost::factory<AA*>();
f["2"] = boost::factory<AB*>();
C test(f);
delete f["1"]();
delete f["2"]();
delete f["1"]();
delete f["2"]();
C test2(f);
delete f["1"]();
delete f["2"]();
delete f["1"]();
delete f["2"]();
}
Prints
entry for 1 present 1
entry for 2 present 1
AA::AA()
AB::AB()
AA::AA()
AB::AB()
entry for 1 present 1
entry for 2 present 1
AA::AA()
AB::AB()
AA::AA()
AB::AB()
Related
Can I send an instance to a function not by using the . operator?
For example:
// header file
class A
{
public:
void foo() {std::cout << "Hello" << std::endl;}
};
// main file
A instance = new A;
instance.foo();
// instead do something like this
A::foo(instance);
Can I do something like that?
Yes, you can indirectly via std::invoke:
#include <functional>
#include <iostream>
struct A {
void foo() {
std::cerr << "hi\n";
}
};
int main() {
A a;
std::invoke(&A::foo,a);
}
But std::invoke's implementation will internally probably just apply the .* operator.
You're more than welcome to use the pointer to member syntax.
A instance;
auto fn = &A::foo;
(instance.*fn)();
.* is a different operator than .. Whether this is more readable is left as an exercise to the reader (hint: it's not)
I am new to writing exceptions in c++ and I am struggling with an error. I won't get very much into detail 'cause I don't think this is relevant for the problem that I have.
#ifndef _STUDENT_H_
#define _STUDENT_H_
#include <string>
#include <map>
#include <vector>
#include <stdexcept>
#include <iostream>
class NoMarkException: public exception
{
public: NoMarkException():exception(){
cout<< "No marks were found." << endl;
}/*
NoMarkException(const string &name){
cout << "No marks for " << name << " were found."<< endl;
}*/
};
#endif
This is my NoMarkException class
float Student::getMaxMark() const throw(NoMarkException) {
if (marks.empty()) {
throw NoMarkException::NoMarkException();
}
float final = 0;
for (it = marks.begin(); it != marks.end(); it++) {
if ((*it).second > final) {
final = (*it).second;
}
}
return final;
}
And this is my Student.cpp
When I am building the project I get error: cannot call constructor 'NoMarkException::NoMarkException' directly
Any ideas why it is causing the problem?
if (marks.empty()) {
throw NoMarkException();
}
The error you get does not actually have anything to do with the fact you're using an exception class. The problem is that you're trying to instantiate an object of class NoMarkException by explicitly calling the (default) constructor, NoMarkException::NoMarkException(). In C++ you don't call constructors explicitly; rather, when you define a new variable, an appropriate constructor gets called. For example
void foo() {
std::vector<int> v(5);
NoMarkException my_exception();
NoMarkException my_other_exception();
}
or, using equivalent but more appropriate due to recent language changes:
void foo() {
std::vector<int> v { 5 };
NoMarkException my_exception { };
NoMarkException my_other_exception { };
}
In this case (both syntax alternatives), the constructors:
std::vector<int>::vector(std::vector<int>::size_type count)
NoMarkException::NoMarkException()
NoMarkException::NoMarkException()
are called (*).
In your case, you simply need to replace the explicit call you make to NoMarkException::NoMarkException() in the throw with an instantiation of NoMarkException object, i.e. your statement will be:
throw NoMarkException();
(*) - actually, the vector constructor that's called has a few more parameters which take their default values. See here.
I have a bit of trouble understanding a std::bind call.
In the following example:
#include <functional>
#include <iostream>
#include <memory>
class Notifier
{
public:
Notifier(std::function<void(Notifier&)> on_notify)
:on_notify_(on_notify)
{ }
void notify()
{
if (on_notify_)
on_notify_(*this);
}
std::function<void(Notifier&)> on_notify_;
};
struct Manager
{
Manager()
{
n_ = std::make_unique<Notifier>(std::bind(&Manager::trigger, this));
}
void trigger()
{
std::cout << "notified" << std::endl;
}
std::unique_ptr<Notifier> n_;
};
int main()
{
Manager s;
s.n_->notify();
}
I don't understand how on_notify_(*this); calls back the functor with a Notifier& parameter, but the functor created by bind doesn't specify it.
The calls result correctly to the void notify() method, but I don't understand what exactly will be the functor created by bind to result in this.
If I were to write a lambda instead, I would need to specify the parameter, otherwise it would compile.
What kind of operation does bind here behind my back? :-)
std::bind basically ignores the invalid given argument according to this.
If some of the arguments that are supplied in the call to g() are not matched by any placeholders stored in g, the unused arguments are evaluated and discarded.
It might surprise you that when even more absurd arguments are provided, the binded functor can still successfully reach Manager::trigger() as follows:
#include <functional>
#include <iostream>
#include <memory>
// Some classes that have nothing to do with on_notify_
class AAA {};
class BBB {};
class Notifier
{
public:
Notifier(std::function<void(AAA&, BBB&)> on_notify)
:on_notify_(on_notify)
{ }
void notify()
{
if (on_notify_)
{
// Arguments not matching.
AAA a{};
BBB b{};
// Invoke with them.
on_notify_(a, b);
}
}
std::function<void(AAA&, BBB&)> on_notify_;
};
struct Manager
{
Manager()
{
n_ = std::make_unique<Notifier>(std::bind(&Manager::trigger, this));
}
void trigger()
{
std::cout << "it's also notified!" << std::endl;
}
std::unique_ptr<Notifier> n_;
};
int main()
{
Manager s;
s.n_->notify();
}
Live demo is here.
What do I declare with the following definition:
void (*bar)(A*){ }; //1
My first thought was that I declare and define function pointer and a function the pointer point to. But it's wrong, because any call to the bar() leads to a segmentation fault:
#include <iostream>
#include <vector>
#include <memory>
struct A{ };
void foo(A*){ std:cout << "foo" << std::endl; }
void (*bar)(){ };
int main(){
bar();
}
Moreover, I can't imbed any statement into the "definition":
void (*bar)(A*){ std::cout << "foo" << std::endl };
yeilds compile-time error.
So, what does the declaration //1 mean?
This statement:
void (*bar)(A*){ };
declares a variable named bar of type void(*)(A*), ie "pointer to function taking pointer to A and returning void", and zero-initializes it. Thus, it's equivalent to this:
void (*bar)(A*) = nullptr;
Obviously, when calling this bar, a segfault should be no surprise.
It's not possible to declare a function and a pointer to that function in a single declaration.
When you say
void (*bar)(A*){ }; //1
it means "bar" is a function pointer which can point to some function which takes "A*" as parameter.
In your case, it is not pointing to any function yet.
to make it working use,
void (*bar)(A*) = foo;
This means you have declared a function pointer that points to nothing at the moment. You should able to validate that using a debugger.
void (*bar)(A*){ }; //1
You could make the pointer point to a function like this:
void foo(A*){ std::cout << "foo" << std::endl };
bar = &foo;
And call it like this now:
A a;
bar(&a);
Full snippet:
#include <iostream>
class A {};
void (*bar)(A*){};
void foo(A*) { std::cout << " foo " << std::endl;}
int main() {
A a;
bar = &foo;
bar(&a);
}
Your code should be changed to the following code.
#include <iostream>
#include <vector>
#include <memory>
struct A{ };
void foo(A*){ std::cout << "foo" << std::endl; }
void (*bar)(A*);
int main(){
A a;
bar = &foo;
bar(&a);
}
To declare an actual function, get rid of the (*) portion around the function name:
void bar(A*){ std::cout << "foo" << std::endl };
https://ideone.com/UPIYxg
So, what does the declaration //1 mean?
It is just a comment.
I had encountered a problem while using Loki::Singleton, Loki::SmartPtr, and std::vector under VC express 2008. Following is my source.
#include <iostream>
#include <vector>
#include <loki/Singleton.h>
#include <loki/SmartPtr.h>
class Foo {
public:
std::vector<Loki::SmartPtr<Foo>> children ;
void add() {
Loki::SmartPtr<Foo> f = new Foo ;
children.push_back(f) ;
}
Foo () {
}
~Foo () {
}
} ;
typedef Loki::SingletonHolder<Foo> SingletonFoo ;
int main ()
{
std::cout << "Start" << std::endl ;
SingletonFoo::Instance().add() ;
std::cout << "End" << std::endl ;
}
Compiling and linking has no problem, but after the program finished, an error pops:
Windows has triggered a breakpoint in test.exe.
This may be due to a corruption of the heap, which indicates a bug in test.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while test.exe has focus.
The output window may have more diagnostic information.
It seems some memory are deleted twice, I am quite not sure. Is that a bug of VC or I miss used Loki?
Thanks in advance.
As you're using VC, you should be able to run your code in debug mode, step by stp (F10,F11) to see where it breaks.
Anyway, looking at the Loki singleton code, it seems that the error comes from the assert in SingletonHolder::DestroySingleton() :
SingletonHolder<T, CreationPolicy, L, M, X>::DestroySingleton()
00837 {
00838 assert(!destroyed_); // there, but it's a wild guess
00839 CreationPolicy<T>::Destroy(pInstance_);
00840 pInstance_ = 0;
00841 destroyed_ = true;
00842 }
That function seems to be called by the LifetimePolicy (here DefaultLifetime) as this code suggests :
00800 template
00801 <
00802 class T,
00803 template <class> class CreationPolicy,
00804 template <class> class LifetimePolicy,
00805 template <class, class> class ThreadingModel,
00806 class MutexPolicy
00807 >
00808 void SingletonHolder<T, CreationPolicy,
00809 LifetimePolicy, ThreadingModel, MutexPolicy>::MakeInstance()
00810 {
00811 typename ThreadingModel<SingletonHolder,MutexPolicy>::Lock guard;
00812 (void)guard;
00813
00814 if (!pInstance_)
00815 {
00816 if (destroyed_)
00817 {
00818 destroyed_ = false;
00819 LifetimePolicy<T>::OnDeadReference();
00820 }
00821 pInstance_ = CreationPolicy<T>::Create();
00822 LifetimePolicy<T>::ScheduleDestruction(pInstance_, // here
00823 &DestroySingleton);
00824 }
00825 }
I'm not sure why it is called twice, but I guess the pointer to the singleton is first destroyed (the pointer, not the instance) on the SingletonHolder instance destruction and then the LifetimePolicy try to call it's DestroySingleton() function...
But I might be wrong, you'll have to check that.
IMR, you can't use certain smart pointers in stl containers, and this is the exact problem that occurs. If memory serves, it has to do with how the stl containers copy the values not conforming to how smart pointers expect to be used.
Loki's smart pointers have no problems with STL containers. If you re-write this sample this way:
#include <iostream>
#include <vector>
#include <loki/Singleton.h>
#include <loki/SmartPtr.h>
class Foo {
public:
std::vector<Loki::SmartPtr<Foo>> children ;
void add() {
Loki::SmartPtr<Foo> f = new Foo ;
children.push_back(f) ;
}
Foo () {
}
~Foo () {
}
} ;
// typedef Loki::SingletonHolder<Foo> SingletonFoo ;
int main ()
{
Loki::SmartPtr<Foo> root = new Foo;
std::cout << "Start" << std::endl ;
// SingletonFoo::Instance().add() ;
root->add();
std::cout << "End" << std::endl ;
}
it works without any problems.
What is happening here, is that same class isn't supposed be used as Loki::Singleton and in Loki::SmartPtr at the same time - it's created and destroyed directly in Loki::Singleton, but reference count is maintained for Loki::SmartPtr.
But if you use Loki::SmartPtr<Foo> as parameter of Loki::Singleton it works! The only modification you have to make to your code is a specialization of Loki::CreateUsingNew class to create Loki::SmartPtr<Foo> initialized with freshly created Foo:
#include <iostream>
#include <vector>
#include <loki/Singleton.h>
#include <loki/SmartPtr.h>
class Foo {
public:
std::vector<Loki::SmartPtr<Foo>> children ;
void add() {
Loki::SmartPtr<Foo> f = new Foo ;
children.push_back(f) ;
}
Foo () {
}
~Foo () {
}
};
namespace Loki {
template<class T>
struct CreateUsingNew<class Loki::SmartPtr<T>> {
static Loki::SmartPtr<T>* Create()
{ return new Loki::SmartPtr<T>(new T); }
static void Destroy(Loki::SmartPtr<T>* p)
{ delete p; }
};
}
typedef Loki::SingletonHolder<Loki::SmartPtr<Foo>> SingletonFoo ;
int main ()
{
std::cout << "Start" << std::endl ;
SingletonFoo::Instance()->add() ;
std::cout << "End" << std::endl ;
}