Use union to defer member variable construction - c++

I want to defer the construction of my member variable until the constructor's body and I am trying to use union to do that. Until now, it's achieving what I want but I want to ask is there any reason I shouldn't do this?
Example:
#include <iostream>
struct A {
A() {
std::cout << "Construct A" << std::endl;
}
~A() {
std::cout << "Destruct A" << std::endl;
}
};
struct B {
A a;
};
template <typename T>
union U {
char a{};
T buffer;
U() {}
~U() {
buffer.~T();
}
};
struct C {
U<B> u;
C() {
try {
new (&u.buffer) B();
} catch (...) {
}
}
};
Edit: Add sample usage

One of the reason you should not use the work around is that it does not make sense.
Apply try-catch on hole constructor will work well.
struct C {
A a;
C() try {
} catch (...) {
}
};

std::optional seems to be a great way to do this if you're at C++17.
#include <iostream>
#include <optional>
#include <stdexcept>
struct A {
A(bool fail = false) {
std::cout << "Attempting to construct A" << std::endl;
if (fail) {
throw std::runtime_error("Failed to construct A");
}
else {
std::cout << "Succeeded in constructing A" << std::endl;
}
}
~A() {
std::cout << "Destruct A" << std::endl;
}
};
struct B {
std::optional<A> a;
B(bool fail = false) {
try {
a.emplace(fail);
}
catch (std::runtime_error& ex) {
// fall back to a safe construction
std::cout << "Falling back to safe A construction" << std::endl;
a.emplace();
}
}
};
int main() {
{
B b_good; // should be fine
}
{
B B_bad(true); // should catch the exception and fall back
}
}
output:
Attempting to construct A
Succeeded in constructing A
Destruct A
Attempting to construct A
Failed to construct A
An option that forgoes the size of std::optional is to have the unallocated buffer, but (for type safety) access it through a reference.
#include <iostream>
#include <optional>
#include <stdexcept>
struct A {
A(bool fail = false) {
std::cout << "Attempting to construct A" << std::endl;
if (fail) {
throw std::runtime_error("Failed to construct A");
}
else {
std::cout << "Succeeded in constructing A" << std::endl;
}
}
~A() {
std::cout << "Destruct A" << std::endl;
}
};
struct B {
char a_buff_[sizeof(A)];
A& a_;
B(bool fail = false) : a_(*reinterpret_cast<A*>(a_buff_)) {
try {
new (&a_) A(fail);
}
catch (std::runtime_error& ex) {
std::cout << ex.what() << std::endl;
std::cout << "Falling back to safe A construction" << std::endl;
new (&a_) A();
}
}
~B() { a_.~A(); }
B(const B& other) : a_(other.a_) {}
B& operator=(const B& other) {
a_ = other.a_;
}
};
int main() {
{
B b_good; // should be fine
}
{
B b_bad(true); // should catch the exception and fall back
}
}
Attempting to construct A
Succeeded in constructing A
Destruct A
Attempting to construct A
Failed to construct A
Falling back to safe A construction
Attempting to construct A
Succeeded in constructing A
Destruct A

Related

Pass constructor arguments to member object

I am sure this question has been answered before, but I am unable to find a satisfactory answer. Take the following example:
class A {
public:
A(int a, int b, int c);
//...
};
class B {
public:
B(...);
private:
A _a0;
A _a1;
A _a2;
A _a3;
};
Class B contains multiple instances of class A. I want to represent that B "owns" all of these instances. From what I know, there are a couple ways to represent this
The instances of A are declare as direct members of B (as I have shown), and thus the memory of the A instances is directly inside the B class.
B contains a bunch of unique_ptr objects to the A classes
Use the Builder design pattern to do the creation on step at a time
The reason I don't want to use (2) and (3) is that I want NO heap allocation of these objects (I am writing for an embedded system).
The problem with (1) is, since each A requires 3 constructor parameters and these parameters are not provided by B but rather by the application writer (i.e., B merely owns and uses these instances of A but does not need to know how to create them), I have the bad option of passing 12 arguments to the constructor of B in order to create all 4 As.
I am wondering if another option would be to write the constructor of B such that it takes r-values to As and then move these As into B?
For example:
class B {
public:
B(A&& a0, A&& a1, A&& a2, A&& a3) :
_a0(std::move(a0)),
_a1(std::move(a1)),
_a2(std::move(a2)),
_a3(std::move(a3))
{
}
private:
A _a0;
A _a1;
A _a2;
A _a3;
};
The one problem I can see which this solution is, what if A is a class which points/refers to some "global" resource. The constructor of A should initialize this resource and the destructor should de-initialize this resource. If A is moved, the reference/pointer to the resource also has to be moved AND the old copy of A has to be placed in some valid state which does not de-initialize the resource because ownership has been transferred. What would be the correct way to represent this?
So, your main problem is designing class A. From your description looks like it should be non-copyable, but move-constructible (and move-assignable):
The one problem I can see which this solution is, what if A is a class
which points/refers to some "global" resource. The constructor of A
should initialize this resource and the destructor should
de-initialize this resource. If A is moved, the reference/pointer to
the resource also has to be moved AND the old copy of A has to be
placed in some valid state which does not de-initialize the resource
because ownership has been transferred.
The usual way to create such a class is by using unique_ptr with a custom deleter. Suppose, you have class Resource and
Resource* init_resource(int a);
void deinit_resource(Resource*);
Then, your class A may look like:
class A {
public:
A(int a, int b, int c)
: r( init_resource(a) )
{
//...
}
private:
std::unique_ptr<Resource, deinit_resource> r;
//...
};
With this class A, your constructor design of class B will work, but this is not the only way. If you like Builder pattern but cannot use dynamic memory, then std::optional is your friend. For example:
class B
{
public:
B(){}
void set_A1(int a, int b, int c)
{
a1_ = A(a, b, c);
}
//...
private:
std::optional<A> a1_;
//...
};
Here is a solution I put together that seems to work correctly
#include <assert.h>
#include <utility>
#include <cstdint>
#include <iostream>
#include <atomic>
/*
* Some global resource
* On an embedded system, this would be the peripherals/special-purpose registers
*/
static unsigned int resource1 = 0;
static unsigned int resource2 = 0;
/*
* Often, an SDK for an MCU will provide #define statements which contain the
* the start address (as an integer) of the peripheral register(s)
*/
#define RESOURCE1_ADDR (std::intptr_t)(&resource1)
#define RESOURCE2_ADDR (std::intptr_t)(&resource2)
template <typename T>
class ResourceManager;
/**
* #brief A handle to a particular resource managed by a ResourceManager
* #note Similar to unique_ptr, a ResourceHandle may only be moved
*/
template <typename T>
class ResourceHandle {
public:
~ResourceHandle() {
std::cout << "ResourceHandle::~ResourceHandle()" << std::endl;
}
/**
* #brief Helper method to release the resource managed by this handle back
* to its appropriate resource manager.
*/
inline void release() {
assert(_addr != 0);
_manager.release(std::move(*this));
}
/**
* #brief Copy constructor
* #note Deleted because ResourceHandle is move-only
*/
ResourceHandle(const ResourceHandle& other) = delete;
/**
* #brief Assignment operator
* #note Deleted because ResourceHandle is move-only
*/
const ResourceHandle& operator=(const ResourceHandle&) = delete;
ResourceHandle(ResourceHandle&& other) :
_manager(other._manager),
_addr(other._addr)
{
std::cout << "ResourceHandle::ResourceHandle(ResourceHandle&&)" << std::endl;
assert(_addr != 0);
other._addr = 0;
}
ResourceHandle& operator=(ResourceHandle&& other) {
std::cout << "ResourceHandle::operator=(ResourceHandle&&)" << std::endl;
if (this != &other) {
_addr = other._addr;
other._addr = 0;
}
return *this;
}
operator T*() const {
assert(_addr != 0);
return reinterpret_cast<T*>(_addr);
}
T* operator->() const { return operator T*(); }
inline bool isValid() const { return _addr != 0; }
protected:
ResourceHandle(ResourceManager<T>& manager, std::intptr_t addr) :
_manager(manager),
_addr(addr)
{
std::cout << "ResourceHandle::ResourceHandle(ResourceManager<T>&, std::intptr_t)" << std::endl;
}
private:
ResourceManager<T>& _manager;
/**
* #brief The integer address of the resource being mamaged by this handle
* #note Set to 0 when invalid
*/
std::intptr_t _addr;
friend class ResourceManager<T>;
};
/**
* #brief Class which manages a particular resource by allowing a ResourceHandle
* to be "obtained" and "released"
*/
template <typename T>
class ResourceManager {
public:
constexpr ResourceManager(std::intptr_t addr) :
_resource(*this, addr)
{
}
constexpr ResourceHandle<T> obtain() {
std::cout << "ResourceHandle::obtain()" << std::endl;
assert(_resource.isValid());
return std::move(_resource);
}
constexpr void release(ResourceHandle<T> r) {
std::cout << "ResourceHandle::release()" << std::endl;
assert(!_resource.isValid());
_resource = std::move(r);
}
private:
ResourceHandle<T> _resource;
};
/**
* #brief Example class which "uses" (i.e., takes ownership of) a resource
* via a ResourceHandle
*/
class ResourceUser {
public:
ResourceUser(ResourceHandle<unsigned int> r) :
_r(std::move(r))
{
std::cout << "ResourceUser::ResourceUser(ResourceHandle<unsigned int>)" << std::endl;
//Init
std::cout << "ResourceUser -> Init resource" << std::endl;
*_r = 0;
}
~ResourceUser() {
std::cout << "ResourceUser::~ResourceUser()" << std::endl;
if (_r.isValid()) {
std::cout << "ResourceUser -> Cleanup resource" << std::endl;
*_r = 0;
_r.release();
}
}
ResourceUser(ResourceUser&& other) :
_r(std::move(other._r))
{
std::cout << "ResourceUser::ResourceUser(ResourceUser&&)" << std::endl;
}
void set(unsigned int x) {
std::cout << "ResourceUser::set()" << std::endl;
*_r = x;
}
private:
ResourceHandle<unsigned int> _r;
};
/**
* #brief Example class which "owns" two ResourceUser objects
*/
class ResourceUserUser {
public:
ResourceUserUser(ResourceUser&& a, ResourceUser&& b) :
_a(std::move(a)),
_b(std::move(b))
{
std::cout << "ResourceUserUser::ResourceUserUser()" << std::endl;
}
~ResourceUserUser() {
std::cout << "ResourceUserUser::~ResourceUserUser()" << std::endl;
}
void foo() {
std::cout << "ResourceUserUser::foo()" << std::endl;
_a.set(10);
_b.set(20);
}
private:
ResourceUser _a;
ResourceUser _b;
};
class Resource1 : public ResourceManager<unsigned int> {
public:
inline static ResourceManager<unsigned int>& instance() { return _instance; }
private:
static ResourceManager<unsigned int> _instance;
};
class Resource2 : public ResourceManager<unsigned int> {
public:
inline static ResourceManager<unsigned int>& instance() { return _instance; }
private:
static ResourceManager<unsigned int> _instance;
};
ResourceManager<unsigned int> Resource1::_instance(RESOURCE1_ADDR);
ResourceManager<unsigned int> Resource2::_instance(RESOURCE2_ADDR);
void test1() {
std::cout << std::endl << "BEGIN test1()" << std::endl;
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
ResourceUser user(Resource1::instance().obtain());
user.set(20);
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
std::cout << "END test1()" << std::endl;
}
void test2() {
std::cout << std::endl << "BEGIN test2()" << std::endl;
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
ResourceUserUser user(ResourceUser{Resource1::instance().obtain()}, ResourceUser{Resource2::instance().obtain()});
user.foo();
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
std::cout << "END test2()" << std::endl;
}
void test3() {
std::cout << std::endl << "BEGIN test3()" << std::endl;
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
ResourceUser user1(Resource1::instance().obtain());
ResourceUserUser user2(ResourceUser{Resource1::instance().obtain()}, ResourceUser{Resource2::instance().obtain()});
user2.foo();
std::cout << "resource1 = " << resource1 << std::endl;
std::cout << "resource2 = " << resource2 << std::endl;
std::cout << "END test3()" << std::endl;
}
If you execute test2() the output is
ResourceHandle::ResourceHandle(ResourceManager<T>&, std::intptr_t)
ResourceHandle::ResourceHandle(ResourceManager<T>&, std::intptr_t)
BEGIN test2()
resource1 = 0
resource2 = 0
ResourceHandle::obtain()
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceHandle<unsigned int>)
ResourceUser -> Init resource
ResourceHandle::obtain()
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceHandle<unsigned int>)
ResourceUser -> Init resource
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceUser&&)
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceUser::ResourceUser(ResourceUser&&)
ResourceUserUser::ResourceUserUser()
ResourceUser::~ResourceUser()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceUser::~ResourceUser()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceUserUser::foo()
ResourceUser::set()
ResourceUser::set()
resource1 = 10
resource2 = 20
END test2()
ResourceUserUser::~ResourceUserUser()
ResourceUser::~ResourceUser()
ResourceUser -> Cleanup resource
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::release()
ResourceHandle::operator=(ResourceHandle&&)
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceUser::~ResourceUser()
ResourceUser -> Cleanup resource
ResourceHandle::ResourceHandle(ResourceHandle&&)
ResourceHandle::release()
ResourceHandle::operator=(ResourceHandle&&)
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
ResourceHandle::~ResourceHandle()
I am curious though, is there any way I can get rid of those extra calls to the move constructor? For example, the ResourceManager calls the move constructor to move the handle out of itself, then the ResourceUser calls the move constructor again.

C++ : custom vtable implementation does not work

I'm trying to implement a custom vtable to better understand a concept of virtual tables and overriding. For this I have the following 'base' class
#pragma once
#include <iostream>
#include <string>
using namespace std::string_view_literals;
struct vtable;
class IdentityDocument {
public:
IdentityDocument()
: vtable_ptr_(&IdentityDocument::VTABLE),
unique_id_(++unique_id_count_)
{
std::cout << "IdentityDocument::Ctor() : "sv << unique_id_ << std::endl;
}
~IdentityDocument() {
--unique_id_count_;
std::cout << "IdentityDocument::Dtor() : "sv << unique_id_ << std::endl;
}
IdentityDocument(const IdentityDocument& other)
: vtable_ptr_(other.vtable_ptr_),
unique_id_(++unique_id_count_)
{
std::cout << "IdentityDocument::CCtor() : "sv << unique_id_ << std::endl;
}
IdentityDocument& operator=(const IdentityDocument&) = delete;
void PrintID() const {
std::cout << "IdentityDocument::PrintID() : "sv << unique_id_ << std::endl;
}
static void PrintUniqueIDCount() {
std::cout << "unique_id_count_ : "sv << unique_id_count_ << std::endl;
}
int GetID() const {
return unique_id_;
}
private:
vtable* vtable_ptr_ = nullptr;
static int unique_id_count_;
static vtable VTABLE;
int unique_id_;
};
struct vtable
{
void (IdentityDocument::* const PrintID)() const;
vtable (
void (IdentityDocument::* const PrintID)() const
) : PrintID(PrintID) {}
};
int IdentityDocument::unique_id_count_ = 0;
vtable IdentityDocument::VTABLE = {&IdentityDocument::PrintID};
And here is another class that must override PrintId method
#pragma once
#include "identity_document.h"
#include <iostream>
#include <string>
#include <ctime>
using namespace std::string_view_literals;
class Passport {
public:
Passport()
: expiration_date_(GetExpirationDate())
{
IdentityDocument* base_ptr = reinterpret_cast<IdentityDocument*>(this);
vtable* vtable_ptr = reinterpret_cast<vtable*>(base_ptr);
vtable_ptr = &Passport::VTABLE;
std::cout << "Passport::Ctor()"sv << std::endl;
}
Passport(const Passport& other)
: identity_(other.identity_)
, expiration_date_(other.expiration_date_)
{
IdentityDocument* base_ptr = reinterpret_cast<IdentityDocument*>(this);
vtable* vtable_ptr = reinterpret_cast<vtable*>(base_ptr);
vtable_ptr = &Passport::VTABLE;
std::cout << "Passport::CCtor()"sv << std::endl;
}
~Passport() {
std::cout << "Passport::Dtor()"sv << std::endl;
}
void PrintID() const {
std::cout << "Passport::PrintID() : "sv << identity_.GetID();
std::cout << " expiration date : "sv << expiration_date_.tm_mday << "/"sv << expiration_date_.tm_mon << "/"sv
<< expiration_date_.tm_year + 1900 << std::endl;
}
void PrintVisa(const std::string& country) const {
std::cout << "Passport::PrintVisa("sv << country << ") : "sv << identity_.GetID() << std::endl;
}
private:
IdentityDocument identity_;
const struct tm expiration_date_;
static vtable VTABLE;
tm GetExpirationDate() {
time_t t = time(nullptr);
tm exp_date = *localtime(&t);
exp_date.tm_year += 10;
mktime(&exp_date);
return exp_date;
}
};
vtable Passport::VTABLE = {reinterpret_cast<void (IdentityDocument::*)() const>(&Passport::PrintID)};
And a short demo :
int main() {
array<IdentityDocument*, 1> docs = { (IdentityDocument*)(new Passport()) };
for (const auto* doc : docs) {
doc->PrintID();
}
}
Unfortunately, I see that the 'derived' method was not called. Am I using a wrong approach to implement a vtable concept?
Am I using a wrong approach to implement a vtable concept?
Yes. You have not written any code that reads your vtable, and the C++ compiler will not generate any code to read your vtable either.
When you declare a member function virtual, your compiler needs to call that function in a special way. Any call to that function should be looked up in a vtable.
When a member function is not virtual, your compiler knows that it doesn't need to look up the location of the function. It knows which function to call. No lookup needed.
In your code, you have created a vtable, but this line, calling a non-virtual function:
doc->PrintID();
Does not need a vtable, and does not check for one.
doc is an IdentityDocument*, so doc->PrintID() calls IdentityDocument::PrintID(). No lookup required, no lookup happens.
Finally I simplified my solution and got what I wanted :
#include <iostream>
class A;
struct VTable
{
void (*say_hello)(A*);
};
class A
{
public:
A()
{
vtable.say_hello = A::sayHello;
}
void sayHello()
{
vtable.say_hello(this);
}
static void sayHello(A* a)
{
std::cout << "A::sayHello" << std::endl;
}
VTable vtable;
};
class B
{
public:
B()
{
a.vtable.say_hello = B::sayHello;
}
void sayHello()
{
a.vtable.say_hello((A*)this);
}
static void sayHello(A* a)
{
std::cout << "B::sayHello\n" << std::endl;
}
private:
A a;
};
int main()
{
A* a = (A*)(new B);
a->sayHello();
delete a;
}

Why there is something wrong when invoking ctor in another ctor?

Here is a demo code snippet(https://godbolt.org/z/31Tq3r):
#include<iostream>
class Ctx
{
public:
enum RUN_MOD
{
MOD_RT,
MOD_NRT,
};
Ctx(RUN_MOD runType)
{
if(runType == MOD_RT)
{
Ctx();
}
}
Ctx()
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
void print()
{
std::cout <<"print() m_L=" << m_L << std::endl;
}
private:
void *m_L;
const char* const ARG_TYPE_NOT_MATCH = "the type of argument is not match";
const char* const ARG_NUM_INVALID = "the number of arguments is invalid";
const char* const STACK_OPS_INPUT_ARG_INVALID = "the input argument passed to the stack ops is invalid";
};
int main()
{
Ctx ctx(Ctx::RUN_MOD::MOD_RT);
ctx.print();
}
Here are outputs when invoking the binary program on Ubuntu:
set m_L=0x614c20
print() m_L=0x400ad0
You see the addresses are not the same. I have set m_L by invoking Ctx::Ctx()(which is called by Ctx::Ctx(RUN_MOD runType)) indeed. I am really confused.
Constructor delegation can only be used from inside a constructor’s member initialization list, NOT inside a constructor’s body. This answer shows how to avoid the need to use constructor delegation at all, by creating a common initialization function that multiple constructors can then call as needed.
However, if you did want to use constructor delegation, for whatever reason, then in this case the Ctx() constructor should delegate to the Ctx(RUN_MOD) constructor, not the other way around as you originally attempted, eg:
class Ctx
{
public:
enum RUN_MOD
{
MOD_RT,
MOD_NRT,
};
Ctx(RUN_MOD runType)
{
if (runType == MOD_RT)
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
}
Ctx() : Ctx(MOD_RT) // <— here
{
}
void print()
{
std::cout << "print() m_L=" << m_L << std::endl;
}
private:
void *m_L = nullptr;
const char* const ARG_TYPE_NOT_MATCH = "the type of argument is not match";
const char* const ARG_NUM_INVALID = "the number of arguments is invalid";
const char* const STACK_OPS_INPUT_ARG_INVALID = "the input argument passed to the stack ops is invalid";
};
If you are looking for a clean solution you could use a function that does, what the default constructor should do. This way you don't need constructor delegation, which afaik can't be applied conditional and you don't have to mess with placement new.
Minimal example:
class Ctx
{
private:
void DefaultInit()
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
public:
Ctx(RUN_MOD runType)
{
if(runType == MOD_RT)
{
this->DefaultInit();
}
}
Ctx()
{
this->DefaultInit();
}
}
Calling ctor of any class makes an instance of it, in your posted code it is obvious that allocated m_l in Ctx() is not belong to the object constructed by Ctx(RUN_MOD runType)
try below code
void init_m_l()
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
Ctx(RUN_MOD runType)
{
if(runType == MOD_RT)
init_m_l();
}
Ctx()
{
init_m_l();
}
It's a good answer, but the author deleted it.
I posted it here for more people to study.
his code:
if(runType == MOD_RT)
{
Ctx();
}
creates a temporary Ctx() object, and -- that's it. Nothing more, nothing less. That temporary just gets destroyed as soon as that line of code is finished executing.
There are other major issues with the class, such as using malloc, the class leaks memory due to not following the rule of 3, not initializing all the members (which I addressed by setting m_L to nullptr), etc.
I found a solution, here is the code snippet(https://coliru.stacked-crooked.com/a/964309f60f62dbd4, it works, but I am still trying to understand it):
#include<iostream>
class Ctx
{
public:
enum RUN_MOD
{
MOD_RT,
MOD_NRT,
};
Ctx(RUN_MOD runType)
{
if(runType == MOD_RT)
{
new (this)Ctx();
}
}
Ctx()
{
m_L = malloc(100);
std::cout << "set m_L=" << m_L << std::endl;
}
void print()
{
std::cout <<"print() m_L=" << m_L << std::endl;
}
~Ctx()
{
free(m_L);
}
Ctx(const Ctx&) = delete; //to avoid double free
private:
void *m_L;
const char* const ARG_TYPE_NOT_MATCH = "the type of argument is not match";
const char* const ARG_NUM_INVALID = "the number of arguments is invalid";
const char* const STACK_OPS_INPUT_ARG_INVALID = "the input argument passed to the stack ops is invalid";
};
int main()
{
Ctx ctx(Ctx::RUN_MOD::MOD_RT);
ctx.print();
}

Using boost::signals2::trackable with lambdas

I am using a pattern like this, C++11:
class FooViewController {
void build() {
auto label = ...
network->doWork([] (const Result& r) {
label->setText(r.text);
});
}
}
FooViewController may deconstruct before doWork completes, causing crashes. Looking at boost::signals2, I'm thinking of using boost::signals2::trackable, which works great for my single threaded purposes, with the benefit that I do not have to hold and manage my connections directly, however I'm not sure how to get such a solution working with lambdas.
Here is a working lambda free version:
class Foo : public boost::signals2::trackable {
public:
void bar() {
printf("Fire!");
}
};
Usage:
boost::signals2::signal<void()> signal;
{
Foo test;
signal.connect(boost::bind(&Foo::bar, &test));
signal();
}
signal();
Output:
Fired!
// Note a second 'Fired!' did not occur, which is correct behavior
Two goals:
1-- I'd like to do something like:
signal.connect(boost::bind([] {
printf("Fired!");
}, &test));
Which would NOT call the lambda after test is torn down.
2-- I do not want to directly manage the connection objects returned by .connect.
As can be seen here: "Use of the trackable class is not recommended for new code"
Perhaps choose to go with scoped_connection or track instead.
Example:
#include <iostream>
#include <memory>
#include <boost/signals2.hpp>
struct short_lived : public boost::signals2::scoped_connection {
public:
short_lived(const boost::signals2::connection &conn) : boost::signals2::scoped_connection{conn}
{ }
~short_lived() {
std::cout << "I'm dying...1!" << std::endl;
}
};
int main() {
typedef boost::signals2::signal<void()> sig_type;
sig_type s1;
{
/* boost::signals2::scoped_connection */ short_lived conn{s1.connect([]() {
std::cout << "Fire1!" << std::endl;
})};
s1();
}
s1();
std::cout << std::endl;
{
auto lam = []() {
std::cout << "Fire2!" << std::endl;
};
/* shared_ptr with custom deleter that does not delete (since we didn't use new),
but prints a message */
std::shared_ptr<decltype(lam)> sptr{&lam, [](decltype(lam) *) { std::cout << "I'm dying...2!" << std::endl; }};
s1.connect(sig_type::slot_type(lam).track_foreign(sptr));
s1();
}
s1();
return 0;
}
http://melpon.org/wandbox/permlink/c8LHGIp8ArkKsnWA
Found the answer referencing trackable_test.cpp:
struct short_lived : public boost::signals2::trackable {
~short_lived() {
cout << "I'm dying...!" << std::endl;
}
};
void main() {
typedef boost::signals2::signal<void()> sig_type;
sig_type s1;
short_lived* shorty = new short_lived();
s1.connect(boost::bind<void>([](const short_lived*) {
cout << "Fire!" << std::endl;
}, shorty));
s1();
delete shorty;
s1();
}
Output
Fire!
I'm dying...!
...and a multiple params example (boost::bind refresher):
typedef boost::signals2::signal<void(int)> sig_type;
// ...same...
s1.connect(boost::bind<void>([](const short_lived*, int cannon) {
cout << "Fire " << cannon << "!" << std::endl;
}, shorty, _1));
s(1);
delete shorty;
s(2);
Output
Fire 1!
I'm dying...!
You can code something similar using shared/weak pointers:
Live On Coliru
#include <boost/signals2.hpp>
#include <boost/make_shared.hpp>
#include <boost/weak_ptr.hpp>
#include <iostream>
class Foo : public boost::signals2::trackable {
public:
void bar() {
printf("Fire!\n");
}
};
int main() {
boost::signals2::signal<void()> signal;
{
auto test = boost::make_shared<Foo>();
signal.connect([wp = boost::weak_ptr<Foo>(test)]
{
if (auto sp = wp.lock())
sp->bar();
else
std::cout << "expired\n";
}
);
signal();
}
signal();
}
Prints
Fire!
expired
The strictly c++11 version: Live On Coliru

How to handle the exception?

#include<iostream>
using namespace std;
class test
{
public:
test()
{
cout<<"hello";}
~test()
{
cout<<"hi";
throw "const";
}
void display()
{
cout<<"faq";
}
};
int main()
{
test t;
try{
}
catch(char const *e)
{
cout<<e;
}
t.display();
}
output:
i know by throwing exception from destructor i'm violating basic c++ laws but still i want to know is their any way the exception can be handled.
Your destructor runs outside the try-catch block - t's scope is the main function. but then raising exceptions from a destructor is a Bad IdeaTM.
There's nothing in your try block. Try this:
try
{
test t;
}
catch(char const *e)
{
cout << e;
}
Also, in general throwing an exception in a destructor is a bad idea (as with most rules, there are exceptions).
The creation of your test object must be done inside the try block:
try
{
test t;
t.Display();
}
and a full version:
#include<iostream>
using namespace std;
class test
{
public:
test()
{
cout << "hello" << endl;
}
~test()
{
cout << "hi" << endl;
throw "const";
}
void display()
{
cout << "faq" << endl;
}
};
int main()
{
try
{
test t;
t.display();
}
catch(char const *e)
{
cout << e << endl;
}
}
Why not just call the destructor function explicitly in try block?