Is there a pattern to automatically call a destructor of a placement-new initialized object on the stack when it exits scope? I want to skip the need to memorize to call the destructor explicitly. Or, is there a different method than the placement-new to construct a stack based object with a variable size data[] tail? I use g++.
/* g++ f.cpp -o f.exe */
/* 8< --- f.cpp ---- */
#include <stdio.h>
#include <stdlib.h>
#include <string>
class aclass {
public:
aclass(int size) : size_(size) {};
~aclass() { /* do something */ };
int size_;
char data[0];
};
void f(int size)
{
char v[sizeof(aclass) + size];
aclass *p = new(static_cast<void*>(&v)) aclass(size);
p->~aclass();
}
int main(int argc, char **argv)
{
f(10);
f(100);
return 0;
}
You can create a wrapper class like this:
template <typename T>
class Foo {
private:
T *m_ptr;
public:
Foo(void *area, int size) {
m_ptr = new(area) T(size);
}
Foo(const Foo &) = delete;
~Foo() {
m_ptr->~T();
}
void operator=(const Foo &) = delete;
T *operator->() {
return m_ptr;
}
};
Usage:
void f(int size) {
char v[sizeof(aclass)+size];
Foo<aclass> p(v, size);
p->doSomething(); // call a function from aclass
}
Note that you're using a GCC extension, as size is not a compile-time constant.
If it was a compile-time constant, then you could put v into Foo (and size would be a template parameter), so f would be simpler.
There is already a standard wrapper template class which does this - std::unique_ptr.
Note the caveats in the comments
#include <cstdio>
#include <cstdlib>
#include <string>
#include <memory>
class aclass {
public:
aclass(int size);
~aclass();
int size_;
char data[0]; // this is illegal in standard c++
};
// deleter which only calls destructor, does not deallocate
struct inplace_deleter
{
template<class T>void operator()(T* p) const noexcept
{
p->~T();
}
};
void f(int size)
{
// VLAs are not standard c++. This is a compiler extension on gcc.
char v[sizeof(aclass) + size];
using ptr_type = std::unique_ptr<aclass, inplace_deleter>;
auto p = ptr_type(new(&v) aclass(size));
// auto deleted
}
int main()
{
f(10);
f(100);
return 0;
}
https://godbolt.org/z/qEwld-
Related
I have some problem compiling my code.
I have the following structure:
#include <cstdlib>
using namespace std;
typedef double (*FuncType)(int );
class AnotherClass {
public:
AnotherClass() {};
double funcAnother(int i) {return i*1.0;}
};
class MyClass {
public:
MyClass(AnotherClass & obj) { obj_ = &obj;};
void compute(FuncType foo);
void run();
protected:
AnotherClass * obj_; /*pointer to obj. of another class */
};
void MyClass::compute(FuncType foo)
{
int a=1;
double b;
b= foo(a);
}
void MyClass::run()
{
compute(obj_->funcAnother);
}
/*
*
*/
int main(int argc, char** argv) {
AnotherClass a;
MyClass b(a);
b.run();
return 0;
}
When I try to compile it, it gives:
main.cpp:39:31: error: no matching function for call to ‘MyClass::compute(<unresolved overloaded function type>)’
main.cpp:30:6: note: candidate is: void MyClass::compute(double (*)(int))
What's wrong here?
p/s/ AnotherClass * obj_; should stay like that because I write some function to the big library and can't change it.
-------------- working version by Benjamin -------
#include <cstdlib>
using namespace std;
class AnotherClass {
public:
AnotherClass() {};
double funcAnother(int i) {return i*1.0;}
};
struct Foo
{
/*constructor*/
Foo(AnotherClass & a) : a_(a) {};
double operator()(int i) const
{
return a_.funcAnother(i);
}
AnotherClass & a_;
};
class MyClass {
public:
MyClass(AnotherClass & obj) { obj_ = &obj;};
template<typename FuncType>
void compute(FuncType foo);
void run();
protected:
AnotherClass * obj_; /*pointer to obj. of another class */
};
template<typename FuncType>
void MyClass::compute(FuncType foo)
{
int a=1;
double b;
b= foo(a);
}
void MyClass::run()
{
Foo f(*obj_);
compute(f);
}
/*
*
*/
int main(int argc, char** argv) {
AnotherClass a;
MyClass b(a);
b.run();
return 0;
}
Thank you everybody very much for the help!
Since,
funcAnother(int i);
is a member function it passes an implicit this and then the prototype does not match the type of your function pointer.
The typedef for pointer to member function should be:
typedef double (AnotherClass::*funcPtr)(int);
Here is a modified compilable version of your code. Please check the comments inline to understand the changes, Also I left out the other details, you can add that up.
The following function class will match the signature of your FuncType:
struct Foo
{
AnotherClass & a_;
Foo(AnotherClass & a) a_(a) {}
double operator()(int i) const
{
return a_.funcAnother(i);
}
};
Change MyClass::compute to a template, thusly:
template<typename FuncType>
void MyClass::compute(FuncType foo)
{
int a=1;
foo(a);
}
Then you can call run like this:
void MyClass::run()
{
compute(Foo(*obj_));
}
If your compiler supports lambdas (and there's a good chance it does), then you can forgo the function class and simply define run like this:
void MyClass::run()
{
auto f = [this](int i) {
return obj_->funcAnother(i);
};
compute(f);
}
I have heard people say that "C++ doesn't need placement delete because it wouldn't do anything."
Consider the following code:
#include <cstdlib>
#include <cstdio>
#include <new>
////////////////////////////////////////////////////////////////
template<typename T, typename... ARGS>
T* customNew1(ARGS&&... args) {
printf("customNew1...\n");
auto ret = new T { std::forward<ARGS>(args)... };
printf("OK\n\n");
return ret;
}
template<typename T>
void customDelete1(T *ptr) {
printf("customDelete1...\n");
delete ptr;
printf("OK\n\n");
}
////////////////////////////////
template<typename T, typename... ARGS>
T* customNew2(ARGS&&... args) {
printf("customNew2 alloc...\n");
void *buf = std::malloc(sizeof(T));
printf("customNew2 construct...\n");
auto ret = ::new(buf) T { std::forward<ARGS>(args)... };
printf("OK\n\n");
return ret;
}
template<typename T>
void customDelete2(T *ptr) {
printf("customDelete2 destruct...\n");
// what I want: a "placement delete" which calls the destructor and returns the address that should be passed to the deallocation function
// e.g.
//
// void* ptrToFree = ::delete(ptr);
// std::free(ptrToFree);
//
// equally fine would be a "magic" operator that allows one to obtain said address without actually calling the destructor:
//
// void* ptrToFree = get_deallocation_address_of(ptr);
// ptr->~T();
// std::free(ptrToFree);
ptr->~T();
printf("customDelete2 free...\n");
std::free(ptr);
printf("OK\n\n");
}
////////////////////////////////////////////////////////////////
struct A {
int a;
A() : a(0) {
printf("A()\n");
}
virtual ~A() {
printf("~A()\n");
}
};
struct B {
int b;
B() : b(0) {
printf("B()\n");
}
virtual ~B() {
printf("~B()\n");
}
};
struct C : A, B {
int c;
C() : c(0) {
printf("C()\n");
}
~C() {
printf("~C()\n");
}
};
////////////////////////////////////////////////////////////////
int main() {
C *c1 = customNew1<C>();
A *a1 = c1;
B *b1 = c1;
// Assume c and a will be the same but b is offset
printf("c: %x\n", c1);
printf("a: %x\n", a1);
printf("b: %x\n", b1);
printf("\n");
customDelete1(b1); // <- this will work, the delete expression offsets b1 before deallocing
printf("--------------\n\n");
C *c2 = customNew2<C>();
A *a2 = c2;
B *b2 = c2;
printf("c: %x\n", c2);
printf("a: %x\n", a2);
printf("b: %x\n", b2);
printf("\n");
// customDelete2(b2); // <- this will break
customDelete2(a2); // <- this will work because a2 happens to point at the same address as c2
printf("--------------\n\n");
return 0;
}
As you can see here the destructors, being virtual, are all called properly, but the deallocation of b2 will still fail because b2 points at a different address than c2.
Note that a similar problem arises when one uses placement new[] to construct an array of objects, as described here:
Global "placement" delete[]
However this can be worked around without much trouble by simply saving the array size at the head of your block of memory and handling the array constructor/destructor calls manually in a loop using single object placement new/explicit destructor calls.
On the other hand, I cannot think of any graceful way to solve the problem with multiple inheritance. The "magic" code which retrieves the original pointer from the base pointer within the delete expression is implementation specific, and there's no simple way of "doing it manually" like you can with arrays.
Here is another situation where this becomes a problem, with an ugly hack to work around it:
#include <cstdlib>
#include <cstdio>
#include <new>
////////////////////////////////////////////////////////////////
// imagine this is a library in which all allocations/deallocations must be handled by this base interface
class Alloc {
public:
virtual void* alloc(std::size_t sz) =0;
virtual void free(void *ptr) =0;
};
// here is version which uses the normal allocation functions
class NormalAlloc : public Alloc {
public:
void* alloc(std::size_t sz) override final {
return std::malloc(sz);
}
void free(void *ptr) override final {
std::free(ptr);
}
};
// imagine we have a bunch of other versions like this that use different allocation schemes/memory heaps/etc.
class SuperEfficientAlloc : public Alloc {
void* alloc(std::size_t sz) override final {
// some routine for allocating super efficient memory...
(void)sz;
return nullptr;
}
void free(void *ptr) override final {
// some routine for freeing super efficient memory...
(void)ptr;
}
};
// etc...
////////////////////////////////
// in this library we will never call new or delete, instead we will always use the below functions
// this is used instead of new...
template<typename T, typename... ARGS>
T* customNew(Alloc &alloc, ARGS&&... args) {
printf("customNew alloc...\n");
void *buf = alloc.alloc(sizeof(T));
printf("customNew construct...\n");
auto ret = ::new(buf) T { std::forward<ARGS>(args)... };
printf("OK\n\n");
return ret;
}
// um...
thread_local Alloc *stupidHack = nullptr;
// unfortunately we also have to replace the global delete in order for this hack to work
void operator delete(void *ptr) {
if (stupidHack) {
// the ptr that gets passed here is pointing at the right spot thanks to the delete expression below
// alloc has been stored in "stupidHack" since it can't be passed as an argument...
printf("customDelete free # %x...\n", ptr);
stupidHack->free(ptr);
stupidHack = nullptr;
} else {
// well fug :-D
}
}
// ...and this is used instead of delete
template<typename T>
void customDelete(Alloc &alloc, T *ptr) {
printf("customDelete destruct # %x...\n", ptr);
// set this here so we can use it in operator delete above
stupidHack = &alloc;
// this calls the destructor and offsets the pointer to the right spot to be dealloc'd
delete ptr;
printf("OK\n\n");
}
////////////////////////////////////////////////////////////////
struct A {
int a;
A() : a(0) {
printf("A()\n");
}
virtual ~A() {
printf("~A()\n");
}
};
struct B {
int b;
B() : b(0) {
printf("B()\n");
}
virtual ~B() {
printf("~B()\n");
}
};
struct C : A, B {
int c;
C() : c(0) {
printf("C()\n");
}
~C() {
printf("~C()\n");
}
};
////////////////////////////////////////////////////////////////
int main() {
NormalAlloc alloc;
C *c = customNew<C>(alloc);
A *a = c;
B *b = c;
printf("c: %x\n", c);
printf("a: %x\n", a);
printf("b: %x\n", b);
printf("\n");
// now it works
customDelete(alloc, b);
printf("--------------\n\n");
return 0;
}
This isn't a question really more of just a rant as I'm fairly sure that no magic operator or platform independent method to obtain the address exists. At the company where I work we had a library that used custom allocators with the hack above which worked okay until we had to link it statically with another program that needed to replace global new/delete. Our current solution is simply to ban the deleting of an object through a pointer to a base that can't be shown to always have the same address as the most derived object, but this seems a bit unfortunate. "ptr->~T(); free(ptr);" seems to be a common enough pattern and many people seem to think it's equivalent to a delete expression, but it's not. I'm curious if anyone else has encountered this problem and how they managed to solve it.
If p points to an object of polymorphic class type, you can get the address of the most derived object using dynamic_cast<void*>(p). Thus your customDelete2 can be implemented as follows:
template <class T>
void customDelete2(const T *ptr) {
const void* ptr_to_free = dynamic_cast<const void*>(ptr);
ptr->~T();
std::free(const_cast<void*>(ptr_to_free));
}
(Yes, you can dynamically allocate const objects.)
Since this will only compile for a polymorphic class type, you might want to remove the dynamic_cast to a helper function:
template <class T>
const void* get_complete_object_address(const T* p, std::true_type) {
return dynamic_cast<const void*>(p);
}
template <class T>
const void* get_complete_object_address(const T* p, std::false_type) {
return p;
}
template <class T>
void customDelete2(const T *ptr) {
const void* ptr_to_free = get_complete_object_address(
ptr,
std::integral_constant<bool, std::is_polymorphic<T>::value>{}
);
ptr->~T();
free(const_cast<void*>(ptr_to_free));
}
For the functor:
class F
{
bool proceed;
public:
F():proceed(true) {}
void operator()()
{
while(proceed) {std::cout<<".";}
std::cout<<"stopped\n";
}
void stopIt() {proceed=false;}
};
I'm able to create an object and pass it to a TBB thread (it's now under the std namespace):
F foo;
std::thread t(foo);
This works fine, except that when I call foo.stopIt(), the while loop does not stop. So I assume the foo I'm passing to the thread actually creates a new object.
To prevent that, I tried:
F* foo = new F();
But std::thread t(foo); doesn't work. t(*foo) doesn't work. t(&foo) doesn't work. t(foo->()) doesn't. Tried a few other techniques too. No luck.
So how can I pass the operator()() function to the thread and be able to call stopIt() later?
UPDATE:
In response to Nathan's answer, this is what I tried:
http://coliru.stacked-crooked.com/a/36d70da08c1210f1
#include <algorithm>
#include <list>
#include <vector>
#include <iostream>
#include <numeric>
//#include <random>
#include <functional>
#include <tbb/compat/thread>
template< class T >
T* addressof(T& arg)
{
return reinterpret_cast<T*>(
&const_cast<char&>(
reinterpret_cast<const volatile char&>(arg)));
}
template <class T>
class reference_wrapper {
public:
// types
typedef T type;
// construct/copy/destroy
reference_wrapper(T& ref) : _ptr(addressof(ref)) {}
//reference_wrapper(T&&) = delete;
//reference_wrapper(const reference_wrapper&) noexcept = default;
// assignment
//reference_wrapper& operator=(const reference_wrapper& x) noexcept = default;
// access
operator T& () const { return *_ptr; }
T& get() const { return *_ptr; }
private:
T* _ptr;
};
class F
{
bool proceed;
public:
F():proceed(true) {}
void operator()()
{
while(proceed) {std::cout<<".";}
std::cout<<"stopped\n";
}
void stopIt() {proceed=false;}
};
class ref {
public:
typedef F type;
ref(F& ref) : _ptr(addressof(ref)) {}
operator F& () const { return *_ptr; }
F& get() const { return *_ptr; }
private:
F* _ptr;
};
int main()
{
//using namespace std::literals;
F foo;
std::thread t(ref(foo));
std::cout<<"running";
//std::this_thread::sleep_for(1ms);
foo.stopIt();
//t.join();
}
thread takes it parameters by value. If you need the thread to get the same object that you have in the calling function then you need to wrap it with std::ref
In this case to run the code and get some output we can run:
int main()
{
using namespace std::literals;
F foo;
std::thread t(std::ref(foo));
std::this_thread::sleep_for(1ms);
foo.stopIt();
t.join();
}
Live Example
I implemented the following smart pointer template class:
#ifndef __ProjectManager__mSharedPtr__
#define __ProjectManager__mSharedPtr__
#include <stdio.h>
#include "RefCount.h"
template <class T>
class mSmartPtr {
T *data;
RefCount *rc;
public:
mSmartPtr(T* srcPtr);
mSmartPtr(const mSmartPtr&);
~mSmartPtr();
T* operator->() const;
T& operator*() const;
mSmartPtr<T>& operator=( mSmartPtr&);
mSmartPtr<T> operator()(mSmartPtr&);
};
template<class T>
mSmartPtr<T> mSmartPtr<T>::operator()(mSmartPtr<T>& src) {
return dynamic_cast<??>(src);
}
template <class T>
mSmartPtr<T>::mSmartPtr(T *srcPtr):
data(srcPtr) {
rc = new RefCount();
rc->add();
}
template<class T>
mSmartPtr<T>::~mSmartPtr() {
if (rc->remove() == 0) {
delete data;
delete rc;
}
}
template<class T>
mSmartPtr<T>::mSmartPtr(const mSmartPtr<T> &src):
data(src.data), rc(src.rc) {
rc->add();
}
template <class T>
T* mSmartPtr<T>::operator->() const {
return data;
}
template<class T>
T& mSmartPtr<T>::operator*() const {
return &data;
}
template <class T>
mSmartPtr<T>& mSmartPtr<T>::operator=( mSmartPtr<T> &src) {
if (this != &src) {
if (rc->remove() == 0) {
delete data;
delete rc;
}
data = src.data;
rc = src.rc;
rc->add();
}
return *this;
}
#endif /* defined(__ProjectManager__mSharedPtr__) */
let's say my application contains the following classes:
class Base
{
protected:
...
public:
virtual ~Base() =0;
...
};
class Derived1 : public Base
{
protected:
...
public:
virtual ~Derived1() {}
...
};
class Derived2 : public Base
{
protected:
...
public:
virtual ~Derived2() {}
...
};
and I need store data at the following way:
int int main(int argc, char const *argv[])
{
std::vector<mSmartPtr<Base>> v;
mSmartPtr<Derived1> d1 = foo();
v.push_back(d1);
return 0;
}
I need to fix somehow the cast operator, but how? how do I get the base class in the dynamic cast?
#Guvante
Your code did not work , I modified it as follows but I don't know if will work well
template<class T>
mSmartPtr<T> mSmartPtr<T>::operator ()(mSmartPtr<T>& src) {
mSmartPtr<T> retVal(dynamic_cast<T*>(src.data));
retVal.rc = src.rc;
retVal.rc.Add();
return retVal;
}
I think there is a better alternative to this. Unless you have a different location where you need to be able to do this, you can avoid the headache by changing the way you create the object.
int main(int argc, char const *argv[])
{
std::vector<mSmartPtr<Base>> v;
mSmartPtr<Base> d1 = static_cast<Base*>(foo());
v.push_back(d1);
return 0;
}
Just avoid creating an mSmartPtr that is typed differently than your vector.
In your conversion method extract the underlying pointer and cast it then put it into the new smart pointer. Don't forget to copy the RefCount and ensure that your target class has a virtual destructor (so the correct one gets called no matter which smart pointer gets dispossed last).
I couldn't figure out how to define it externally but an inline definition worked.
//In the definition, replacing this line
//mSmartPtr<T> operator()(mSmartPtr&)
template<class Tdest>
operator mSmartPtr<Tdest>() {
mSmartPtr<Tdest> retVal(static_cast<Tdest*>(data));
retVal.rc = rc;
retVal.rc.Add();
return retVal;
}
In theory you could also add a version that takes a r-value if you are using C++11 but I think that would take a little work to do correctly so I avoided it.
I have some problem compiling my code.
I have the following structure:
#include <cstdlib>
using namespace std;
typedef double (*FuncType)(int );
class AnotherClass {
public:
AnotherClass() {};
double funcAnother(int i) {return i*1.0;}
};
class MyClass {
public:
MyClass(AnotherClass & obj) { obj_ = &obj;};
void compute(FuncType foo);
void run();
protected:
AnotherClass * obj_; /*pointer to obj. of another class */
};
void MyClass::compute(FuncType foo)
{
int a=1;
double b;
b= foo(a);
}
void MyClass::run()
{
compute(obj_->funcAnother);
}
/*
*
*/
int main(int argc, char** argv) {
AnotherClass a;
MyClass b(a);
b.run();
return 0;
}
When I try to compile it, it gives:
main.cpp:39:31: error: no matching function for call to ‘MyClass::compute(<unresolved overloaded function type>)’
main.cpp:30:6: note: candidate is: void MyClass::compute(double (*)(int))
What's wrong here?
p/s/ AnotherClass * obj_; should stay like that because I write some function to the big library and can't change it.
-------------- working version by Benjamin -------
#include <cstdlib>
using namespace std;
class AnotherClass {
public:
AnotherClass() {};
double funcAnother(int i) {return i*1.0;}
};
struct Foo
{
/*constructor*/
Foo(AnotherClass & a) : a_(a) {};
double operator()(int i) const
{
return a_.funcAnother(i);
}
AnotherClass & a_;
};
class MyClass {
public:
MyClass(AnotherClass & obj) { obj_ = &obj;};
template<typename FuncType>
void compute(FuncType foo);
void run();
protected:
AnotherClass * obj_; /*pointer to obj. of another class */
};
template<typename FuncType>
void MyClass::compute(FuncType foo)
{
int a=1;
double b;
b= foo(a);
}
void MyClass::run()
{
Foo f(*obj_);
compute(f);
}
/*
*
*/
int main(int argc, char** argv) {
AnotherClass a;
MyClass b(a);
b.run();
return 0;
}
Thank you everybody very much for the help!
Since,
funcAnother(int i);
is a member function it passes an implicit this and then the prototype does not match the type of your function pointer.
The typedef for pointer to member function should be:
typedef double (AnotherClass::*funcPtr)(int);
Here is a modified compilable version of your code. Please check the comments inline to understand the changes, Also I left out the other details, you can add that up.
The following function class will match the signature of your FuncType:
struct Foo
{
AnotherClass & a_;
Foo(AnotherClass & a) a_(a) {}
double operator()(int i) const
{
return a_.funcAnother(i);
}
};
Change MyClass::compute to a template, thusly:
template<typename FuncType>
void MyClass::compute(FuncType foo)
{
int a=1;
foo(a);
}
Then you can call run like this:
void MyClass::run()
{
compute(Foo(*obj_));
}
If your compiler supports lambdas (and there's a good chance it does), then you can forgo the function class and simply define run like this:
void MyClass::run()
{
auto f = [this](int i) {
return obj_->funcAnother(i);
};
compute(f);
}