|
Had to look at this this week, and figured I'd code dump it here for anyone who comes afterwards. The following is the code as it currently stands. I believe I have incorporated everything from the below comments.
The code posted in my 'Last version still buggy' no longer blows up in Visual Studio 2015 CE with these changes in place.
For your copy/pasting pleasure:
#pragma once
namespace cd {
namespace anyimpl {
struct empty_any {
};
struct base_any_policy {
virtual void static_delete(void** x) = 0;
virtual void copy_from_value(void const* src, void** dest) = 0;
virtual void clone(void* const* src, void** dest) = 0;
virtual void move(void* const* src, void** dest) = 0;
virtual void* get_value(void** src) = 0;
virtual void* get_value(void* const * src) const = 0;
virtual size_t get_size() = 0;
};
template<typename T>
struct typed_base_any_policy : base_any_policy {
virtual size_t get_size() { return sizeof(T); }
};
template<typename T>
struct small_any_policy : typed_base_any_policy<T> {
virtual void static_delete(void** x) override { }
virtual void copy_from_value(void const* src, void** dest) {
*dest = *(reinterpret_cast<void**>((const_cast<void*>(src))));
}
virtual void clone(void* const* src, void** dest) { *dest = *src; }
virtual void move(void* const* src, void** dest) { *dest = *src; }
virtual void* get_value(void** src) { return reinterpret_cast<void*>(src); }
void* get_value(void* const * src) const override {
return reinterpret_cast<void*>(const_cast<void**>(src));
}
};
template<typename T>
struct big_any_policy : typed_base_any_policy<T> {
virtual void static_delete(void** x) override {
if (*x)
delete(*reinterpret_cast<T**>(x));
*x = NULL;
}
virtual void copy_from_value(void const* src, void** dest) {
*dest = new T(*reinterpret_cast<T const*>(src));
}
virtual void clone(void* const* src, void** dest) {
*dest = new T(**reinterpret_cast<T* const*>(src));
}
virtual void move(void* const* src, void** dest) {
(*reinterpret_cast<T**>(dest))->~T();
**reinterpret_cast<T**>(dest) = **reinterpret_cast<T* const*>(src);
}
virtual void* get_value(void** src) { return *src; }
void* get_value(void* const * src) const override { return *const_cast<void**>(src); }
};
template<typename T>
struct choose_policy {
typedef big_any_policy<T> type;
};
template<typename T>
struct choose_policy<T*> {
typedef small_any_policy<T*> type;
};
struct any;
template<>
struct choose_policy<any> {
typedef void type;
};
#define SMALL_POLICY(TYPE) template<> struct choose_policy<TYPE> { \
typedef small_any_policy<TYPE> type; };
SMALL_POLICY(signed char);
SMALL_POLICY(unsigned char);
SMALL_POLICY(signed short);
SMALL_POLICY(unsigned short);
SMALL_POLICY(signed int);
SMALL_POLICY(unsigned int);
SMALL_POLICY(signed long);
SMALL_POLICY(unsigned long);
SMALL_POLICY(float);
SMALL_POLICY(bool);
#undef SMALL_POLICY
template<typename T>
base_any_policy* get_policy() {
static typename choose_policy<T>::type policy;
return &policy;
};
}
struct any {
private:
anyimpl::base_any_policy* policy;
void* object;
public:
template <typename T>
any(const T& x) : policy(anyimpl::get_policy<unsigned int>()), object(NULL) {
assign(x);
}
any() : policy(anyimpl::get_policy<unsigned int>()), object(NULL) {
}
any(const char* x) : policy(anyimpl::get_policy<anyimpl::empty_any>()),
object(NULL) {
assign(x);
}
any(const any& x) : policy(anyimpl::get_policy<anyimpl::empty_any>()),
object(NULL) {
assign(x);
}
~any() {
policy->static_delete(&object);
}
any& assign(const any& x) {
reset();
policy = x.policy;
policy->clone(&x.object, &object);
return *this;
}
template <typename T>
any& assign(const T& x) {
reset();
policy = anyimpl::get_policy<T>();
policy->copy_from_value(&x, &object);
return *this;
}
template<typename T>
any& operator=(const T& x) {
return assign(x);
}
any& operator=(const any & x) {
return assign(x);
}
any& operator()(const any & x) {
policy = x.policy;
policy->copy_from_value(&x.object, &object);
return *this;
}
any& operator=(const char* x) {
return assign(x);
}
any& swap(any& x) {
std::swap(policy, x.policy);
std::swap(object, x.object);
return *this;
}
template<typename T>
T& cast() {
if (policy != anyimpl::get_policy<T>()) {
throw dwl::Exception(_T("Bad 'any' cast"));
}
T* r = reinterpret_cast<T*>(policy->get_value(&object));
return *r;
}
bool empty() const {
return policy == anyimpl::get_policy<anyimpl::empty_any>();
}
void reset() {
policy->static_delete(&object);
policy = anyimpl::get_policy<unsigned int>();
}
template<typename T>
bool isA() {
return policy == anyimpl::get_policy<T>();
}
template <typename T> operator T&() { return cast<T>(); }
template <typename T> operator T&() const { return cast<T>(); }
template<typename T>
T& cast() const {
if (policy != anyimpl::get_policy<T>()) {
throw dwl::Exception(_T("Bad 'any' cast"));
}
T* r = reinterpret_cast<T*>(policy->get_value(&object));
return *r;
}
};
}
Sudden Sun Death Syndrome (SSDS) is a very real concern which we should be raising awareness of. 156 billion suns die every year before they're just 1 billion years old.
While the military are doing their part, it simply isn't enough to make the amount of nukes needed to save those poor stars. - TWI2T3D (Reddit)
|
|
|
|
|
If you want implicit casting so heavy use does not muck up your sweet, sweet code, you will pretty quickly find that you get a compile error when attempting to use const any&.
The fix is as follows:
in base_any_policy, add
virtual void* get_value(void* const * src) const = 0;
in small_any_policy, add
void* get_value(void* const * src) const override { return reinterpret_cast<void*>(const_cast<void**>(src)); }
in big_any_policy, add
void* get_value(void* const * src) const override { return *const_cast<void**>(src); }
in struct any, add
template <typename T> operator T&() { return cast<T>(); }
template <typename T> operator T&() const { return cast<T>(); }
template<typename T>
T& cast() const
{
if (policy != anyimpl::get_policy<T>())
{
throw anyimpl::bad_any_cast();
}
T* r = reinterpret_cast<T*>(policy->get_value(&object));
return *r;
}
Note these changes were applied to the code found in the "Fix the const problem" post.
modified 25-Mar-15 18:18pm.
|
|
|
|
|
Perform the following:
#include "CdAny.h" //Latest version
class Junk {
private:
int i; int j;
};
int main() {
Junk junk;
Junk * junkPtr = &junk;
cd::any orig(junkPtr);
cd::any second;
second = orig;
second = orig;
return 0;
}
As I said, I don't have a solution other than not to use such a construct. But the fact that it fails indicates there may be other failure modes that still need addressed, so keep an eye out for them.
|
|
|
|
|
Hi all, I want to add move constructor and Assignment move operator.
I tried
any(any&& x)
: policy(x.policy), object(x.object)
{
x.policy = nullptr;
x.object = nullptr;
}
But it doesn't work
any help ?
|
|
|
|
|
First, thanks for the class.
I needed it as convenience in some logging class to help in debugging.
I've tried the last version, the one integrated by @pj220_2006 and the following failed:
cdiggins::any st;
assert( st.empty() );
I've solved the issue by dropping the unsigned int fix and putting back in place the initialization with anyimpl::empty_any .
The key fix is that now empty_any has a specialization with small_any_policy instead of the default one, which would use big_any_policy .
Delta's are:
- in implementation namespace:
template<>
struct choose_policy< empty_any > { typedef small_any_policy< empty_any > type; };
- in any class:
template <typename T>
any(const T& x)
: policy( anyimpl::get_policy< anyimpl::empty_any >() ) , object( nullptr )
{
assign(x);
}
any()
: policy( anyimpl::get_policy< anyimpl::empty_any >() ) , object( nullptr )
{
}
void reset()
{
policy->static_delete(&object);
policy = anyimpl::get_policy< anyimpl::empty_any >();
}
|
|
|
|
|
if T has const prefix, some error will be occour. i also check the David's isA template , when T is a type with const prefix for example ( const char), a error is occour.because the variable temp must be initialized. in order to fix const problem, i add help template class ( remove_const ) to remove the const prefix to solve it. i also chenge David's IsA function to avoid using the temp variable.
#ifndef RMW_CDIGGINS_ANY_HPP
#define RMW_CDIGGINS_ANY_HPP
#include <stdexcept>
namespace dwl
{
namespace anyimpl
{
struct bad_any_cast
{
};
struct empty_any
{
};
struct base_any_policy
{
virtual void static_delete( void** x) = 0;
virtual void copy_from_value(void const* src, void** dest) = 0;
virtual void clone(void* const* src, void** dest) = 0;
virtual void move(void* const* src, void** dest) = 0;
virtual void* get_value(void** src) = 0;
virtual size_t get_size() = 0;
};
template<typename T>
struct typed_base_any_policy : base_any_policy
{
virtual size_t get_size() { return sizeof(T); }
};
template<typename T>
struct small_any_policy : typed_base_any_policy<T>
{
virtual void static_delete(void** x) { }
virtual void copy_from_value(void const* src, void** dest)
{
*dest = *(reinterpret_cast<void**>((const_cast<void*>(src))));
}
virtual void clone(void* const* src, void** dest) { *dest = *src; }
virtual void move(void* const* src, void** dest) { *dest = *src; }
virtual void* get_value(void** src) { return reinterpret_cast<void*>(src); }
};
template<typename T>
struct remove_const
{
typedef T type;
};
template<typename T>
struct remove_const<const T>
{
typedef T type;
};
template<typename T>
struct big_any_policy : typed_base_any_policy<T>
{
virtual void static_delete( void** x)
{
if (*x)
{
delete (*reinterpret_cast< remove_const<T>::type**>(x));
}
*x = NULL;
}
virtual void copy_from_value(void const* src, void** dest)
{
*dest = new remove_const<T>::type(*reinterpret_cast<T const*>(src));
}
virtual void clone(void* const* src, void** dest)
{
*dest = new remove_const<T>::type(**reinterpret_cast<T* const*>(src));
}
virtual void move(void* const* src, void** dest)
{
(*reinterpret_cast<remove_const<T>::type**>(dest))->~T();
**reinterpret_cast<remove_const<T>::type**>(dest) = **reinterpret_cast<T* const*>(src);
}
virtual void* get_value(void** src) { return *src; }
};
template<typename T>
struct choose_policy
{
typedef big_any_policy<T> type;
};
template<typename T>
struct choose_policy<T*>
{
typedef small_any_policy<T*> type;
};
struct any;
template<>
struct choose_policy<any>
{
typedef void type;
};
#define SMALL_POLICY(TYPE) template<> struct choose_policy<TYPE> { typedef small_any_policy<TYPE> type; };
SMALL_POLICY(signed char);
SMALL_POLICY(unsigned char);
SMALL_POLICY(signed short);
SMALL_POLICY(unsigned short);
SMALL_POLICY(signed int);
SMALL_POLICY(unsigned int);
SMALL_POLICY(signed long);
SMALL_POLICY(unsigned long);
SMALL_POLICY(float);
SMALL_POLICY(bool);
SMALL_POLICY(const signed char);
SMALL_POLICY(const unsigned char);
SMALL_POLICY(const signed short);
SMALL_POLICY(const unsigned short);
SMALL_POLICY(const signed int);
SMALL_POLICY(const unsigned int);
SMALL_POLICY(const signed long);
SMALL_POLICY(const unsigned long);
SMALL_POLICY(const float);
SMALL_POLICY(const bool);
#undef SMALL_POLICY
template<typename T>
base_any_policy* get_policy()
{
static typename choose_policy<T>::type policy;
return &policy;
};
}
struct any
{
private:
anyimpl::base_any_policy* policy;
void* object;
public:
template <typename T>
any(const T& x) : policy(anyimpl::get_policy<unsigned int>()), object(NULL)
{
assign(x);
}
any() : policy(anyimpl::get_policy<unsigned int>()), object(NULL)
{
}
any(const char* x) : policy(anyimpl::get_policy<anyimpl::empty_any>()),
object(NULL)
{
assign(x);
}
any(const any& x) : policy(anyimpl::get_policy<anyimpl::empty_any>()), object(NULL)
{
assign(x);
}
~any()
{
policy->static_delete(&object);
}
any& assign(const any& x)
{
reset();
policy = x.policy;
policy->clone(&x.object, &object);
return *this;
}
template <typename T>
any& assign(const T& x)
{
reset();
policy = anyimpl::get_policy<T>();
policy->copy_from_value(&x, &object);
return *this;
}
template<typename T>
any& operator=(const T& x)
{
return assign(x);
}
any& operator=(const any & x)
{
reset();
return assign(x);
}
any& operator()(const any & x)
{
policy = x.policy;
policy->copy_from_value(&x.object, &object);
return *this;
}
any& operator=(const char* x)
{
return assign(x);
}
any& swap(any& x)
{
std::swap(policy, x.policy);
std::swap(object, x.object);
return *this;
}
template<typename T>
T& cast()
{
if (policy != anyimpl::get_policy<T>())
{
throw anyimpl::bad_any_cast();
}
T* r = reinterpret_cast<T*>(policy->get_value(&object));
return *r;
}
bool empty() const
{
return policy == anyimpl::get_policy<anyimpl::empty_any>();
}
void reset()
{
policy->static_delete(&object);
policy = anyimpl::get_policy<unsigned int>();
}
bool isA(const any& x) const
{
return policy == x.policy;
}
template<typename T>
bool isA()
{
return policy == anyimpl::get_policy<T>();
}
}; }
#endif
modified 9-Aug-13 4:51am.
|
|
|
|
|
very good 
|
|
|
|
|
Cool!
|
|
|
|
|
cannot through gcc compiler.
Best Regards
|
|
|
|
|
It has been a while, but I finally got around to looking at the issue more deeply. The problem I mentioned in my previous message only cropped up in semi-complicated circumstances, and with constructs evidently not used by anyone else who has used your class. The base problem appears to be that your empty constructor, although it defaults to empty_any, under the hood is defaulting the the big_any_policy which is calling new and delete. That becomes a big problem when the any object changes to holding a different type via copy construction, or operator=().
That issue came up intermittently in my code - sometimes I didn't get an error, other times I did. The trigger seemed to be that often I used 'any' objects in classes which were held in vectors, or other containers, and a lot of copy construction was occurring.
Therefore I had to modify your empty constructors to default to signed int construction, to make them default to small_any_policy. I also modified copy constructors, and created a couple others in order to address all of my usage cases. Another change I just saw is in the copy_from_value routine for the small_any_policy, as commented below. The following isn't guaranteed to be bug-free, but using it no longer results in undefined behavior bug crashes in my program. Feel free to modify it back into your original class, as I've wrapped it in my own namespace for typing convenience on my end.
If you, or anyone sees anything I've missed, please holler. And thank you for your work on this, and making it freely available! It taught me a lot, and is used extensively in my code.
David
#ifndef RMW_CDIGGINS_ANY_HPP
#define RMW_CDIGGINS_ANY_HPP
#include <stdexcept>
namespace dwl {
namespace anyimpl {
struct empty_any {
};
struct base_any_policy {
virtual void static_delete(void** x) = 0;
virtual void copy_from_value(void const* src, void** dest) = 0;
virtual void clone(void* const* src, void** dest) = 0;
virtual void move(void* const* src, void** dest) = 0;
virtual void* get_value(void** src) = 0;
virtual size_t get_size() = 0;
};
template<typename T>
struct typed_base_any_policy : base_any_policy {
virtual size_t get_size() { return sizeof(T); }
};
template<typename T>
struct small_any_policy : typed_base_any_policy<T> {
virtual void static_delete(void** x) { }
virtual void copy_from_value(void const* src, void** dest) {
*dest = *(reinterpret_cast<void**>((const_cast<void*>(src))));
}
virtual void clone(void* const* src, void** dest) { *dest = *src; }
virtual void move(void* const* src, void** dest) { *dest = *src; }
virtual void* get_value(void** src) { return reinterpret_cast<void*>(src); }
};
template<typename T>
struct big_any_policy : typed_base_any_policy<T> {
virtual void static_delete(void** x) {
if (*x)
delete(*reinterpret_cast<T**>(x));
*x = NULL;
}
virtual void copy_from_value(void const* src, void** dest) {
*dest = new T(*reinterpret_cast<T const*>(src));
}
virtual void clone(void* const* src, void** dest) {
*dest = new T(**reinterpret_cast<T* const*>(src));
}
virtual void move(void* const* src, void** dest) {
(*reinterpret_cast<T**>(dest))->~T();
**reinterpret_cast<T**>(dest) = **reinterpret_cast<T* const*>(src);
}
virtual void* get_value(void** src) { return *src; }
};
template<typename T>
struct choose_policy {
typedef big_any_policy<T> type;
};
template<typename T>
struct choose_policy<T*> {
typedef small_any_policy<T*> type;
};
struct any;
template<>
struct choose_policy<any> {
typedef void type;
};
#define SMALL_POLICY(TYPE) template<> struct choose_policy<TYPE> { typedef small_any_policy<TYPE> type; };
SMALL_POLICY(signed char);
SMALL_POLICY(unsigned char);
SMALL_POLICY(signed short);
SMALL_POLICY(unsigned short);
SMALL_POLICY(signed int);
SMALL_POLICY(unsigned int);
SMALL_POLICY(signed long);
SMALL_POLICY(unsigned long);
SMALL_POLICY(float);
SMALL_POLICY(bool);
#undef SMALL_POLICY
template<typename T>
base_any_policy* get_policy() {
static typename choose_policy<T>::type policy;
return &policy;
};
}
struct any {
private:
anyimpl::base_any_policy* policy;
void* object;
public:
template <typename T>
any(const T& x) : policy(anyimpl::get_policy<unsigned int>()), object(NULL) {
assign(x);
}
any() : policy(anyimpl::get_policy<unsigned int>()), object(NULL) {
}
any(const char* x) : policy(anyimpl::get_policy<anyimpl::empty_any>()),
object(NULL) {
assign(x);
}
any(const any& x) : policy(anyimpl::get_policy<anyimpl::empty_any>()), object(NULL) {
assign(x);
}
~any() {
policy->static_delete(&object);
}
any& assign(const any& x) {
reset();
policy = x.policy;
policy->clone(&x.object, &object);
return *this;
}
template <typename T>
any& assign(const T& x) {
reset();
policy = anyimpl::get_policy<T>();
policy->copy_from_value(&x, &object);
return *this;
}
template<typename T>
any& operator=(const T& x) {
return assign(x);
}
any& operator=(const any & x) {
reset();
return assign(x);
}
any& operator()(const any & x) {
policy = x.policy;
policy->copy_from_value(&x.object, &object);
return *this;
}
any& operator=(const char* x) {
return assign(x);
}
any& swap(any& x) {
std::swap(policy, x.policy);
std::swap(object, x.object);
return *this;
}
template<typename T>
T& cast() {
if (policy != anyimpl::get_policy<T>())
throw DwlException(_T("Bad 'any' cast")); T* r = reinterpret_cast<T*>(policy->get_value(&object));
return *r;
}
bool empty() const {
return policy == anyimpl::get_policy<anyimpl::empty_any>();
}
void reset() {
policy->static_delete(&object);
policy = anyimpl::get_policy<unsigned int>();
}
bool isA(const any& x) const {
return policy == x.policy;
}
template<typename T>
bool isA() {
T temp;
return isA(temp);
}
}; }
#endif // RMW_CDIGGINS_ANY_HPP
modified 15-Jul-13 17:35pm.
|
|
|
|
|
Ported my project to the new code and it went into never-never land. After painful debugging, found it occurred after the following scenario:
Have a control which has an 'any' as a user variable. It is defaulted to nothing. Later, that is assigned to a pointer for a class. And even later it gets reassigned to another pointer to a class. The reassignments occur through the '=' operator.
The program was crashing after the first 'pointer-to-pointer' reassignment took place (not the initial assignment to a pointer). Evidently your SMALL_POLICY settings are not occurring for the new reassignments, and the 'delete' operator is being called on a pointer.
I thought about creating a template function like "any::setToPointer([pointer type])", but instead got around it by using the following construct:
SomeClass * p = &something;
any tempSomething(p);
anotherClassAny = tempSomething;
This has fixed the issue, and my program is working again. Not the cleanest syntax. Hope this helps others. If you change the code to fix this, please let me know. Thanks!
|
|
|
|
|
I just updated my projects to use your new code. First, congratulations on the changes - this updated version is SO much cleaner than the original I can almost wrap my head around it! But I was missing the 'type' function of your old version, as my main project using this tested against that. So I came up with the following small addition which makes replacing that functionality much easier.
template<typename T>
bool compatible() {
T temp;
return compatible(temp);
}
Just add this under the definition of the other 'compatible' function. For those readers who try to use it and are unfamiliar with the template terminology, an example invocation would be something like
if (!buttonC->user.compatible<int>()) doSomething();
Pretty simple, and not much of an addition, but hopefully helpful to some.
[Edit] Having used this for an hour, I'm changing 'compatible' to 'isA', as it better describes the usage context. For example,
if (!buttonC->user.isA<int>()) doSomething(); is a richer and more meaningful syntax than the original.
modified 25-Jan-13 1:32am.
|
|
|
|
|
/// Specializations for small types.
#define SMALL_POLICY(TYPE) template<> struct
choose_policy<TYPE> { typedef small_any_policy<TYPE> type; };
94:22: error: 'TYPE' was not declared in this scope
What is the TYPE ?? I am using g++ to compile it.
|
|
|
|
|
Get rid of the line break and it should build:
#define SMALL_POLICY(TYPE) template<> struct choose_policy<TYPE> { typedef small_any_policy<TYPE> type; };
|
|
|
|
|
Hi there, correct me if I'm wrong: my understanding of dynamic typing goes like this:
using the sample code in your article, I would like to do the following:
any a = 42;
cout << a << endl;
a = 13;
cout << a << endl;
a = "hello";
cout << a << endl;
a = std::string("1234567890");
cout << a.cast<std::string>().c_str() << endl;
int n = 42;
a = &n;
cout << *a.cast<int*>() << endl;
any b = true;
cout << b.cast<bool>() << endl;
swap(a, b);
cout << a.cast<bool>() << endl;
a.cast<bool>() = false;
cout << a.cast<bool>() << endl;
return 0;
What I'm saying is that the class as is can do conversion if there is an assignment operator, but in general, if the context of using the "any" variable is ambiguous, the compiler does not really know how to convert the type. In your example, because "<<" operator for cout is overloaded, then, the explicit call to cast() is necessary to tell the compiler which overload to use. However, this is not what I think of dynamic typing. I don't have to do explicit casts to tell the compiler the actual type of "any".
Is there any way that I can modify the class so that I don't have to do explicit casts?
|
|
|
|
|
I agree. It is very clever made,but the syntax is very ugly.
Also, I tried to use in a real project as a generic datasource, but since
it has no info on the actual type it holds, using it as a return type was not
very nice.
Also, it did not handle simple stuff like
any v1=12;
int num=v1;
I though it would be like the Variant type in VB or Delphi, but perhaps this
is not the goal and speed is.
|
|
|
|
|
You could do something a little closer to what you are both looking for by overloading the casting operator in the any class:
template<typename T>
operator T&() {
return cast<T>();
}
This would let you do things like:
cdiggins::any a = 5;
int b = a;
Or:
void my_function(int b) {
}
cdiggins::any a = 5;
my_function(a);
without having to explicitly cast anything.
This takes advantage of C++'s implicit type conversion mechanisms. Unfortunately, these mechanisms start to break down when you are calling overloaded functions (often operator<<, operator=, etc. have a number of overloads). In these cases you will get an "ambiguous overload" error message from the compiler and be forced to use the old explicit casting to resolve the situation.
In my opinion, this is a limitation of the C++ language or at least the implementation thereof. For example, I don't see why C++ shouldn't be able to resolve the implicit conversion on something like:
cdiggins::any a = std::string("Hi");
std::string b;
b = a;
as it is pretty clear that we are assigning to a string and would probably prefer to assign from a string as well if possible. Other cases are obviously not as clear cut.
I hope this perhaps answers your question a bit. There may also be other reasons or considerations why Mr. Diggins chose not to include the casting operator overload so I'll leave that for him to answer.
|
|
|
|
|
we just evaluated this as an alternative to getting "boost" out of our public api ...
on first try/view it looked good ... but the code seems to contain some glitches (especially in copy-c'tor and assignment) ... I'll give some code examples for the found issues, so if somebody want to spent some time on it could fix it ...
Memory Leak example (only with "values" which contain allocated data):
<pre>
cdiggins::any foobar;
while(true)
{
foobar = std::string("12345678901234567890");
}
</pre>
... the assign (with same table) is missing a d'tor on the internal std::string, so the internal memory of std::string wont be freed
... hint: with VC2008 this only happens with strings bigger then 16char (because this std::string impl. contains a special "hack" for short strings)
Crash example (via multiple deletes on the same alloc):
struct foo_s { void* a; void* b; };
cdiggins::any foo = foo_s();
cdiggins::any bar = foo;
foo = bar;
... will crash at end of "block", when foo and bar get freed
|
|
|
|
|
Thank you for finding this problem. I rewrote the whole thing.
The new version is simpler, and I believe fixes the problems you found. Basically only a handful types now support the "small type" policy.
|
|
|
|
|
I think, with this design, you won't be able to find out whether something is stored in cdiggins::any or not. So storing zero or leaving it empty has the same sense. Am i right?
Gokulakannan K.S.
|
|
|
|
|
Right now allocation doesn't take place for types
whose size is <= sizeof( void *).
I think it would be useful if the function table structure
also stored the size of the type.
So for dynamically allocated objects of different classes
but that have the same object size, we can reuse the
memory after calling the destructor for existing object.
any_detail::fxn_ptr_table* x_table = any_detail::get_table<t>::get();
if (table == x_table) {
becomes something like:
any_detail::fxn_ptr_table* x_table = any_detail::get_table<t>::get();
if (table->size_ == x_table->size_ ) {
destruct existing object;
construct new object in place, on existing memory
Anand.
|
|
|
|
|
#include <cstdio>
struct Small {
~Small() { printf("small destructed\n"); }
};
int main()
{
cdiggins::any a;
a = Small();
a = Small();
}
The 2nd assignment fails to call the destructor of the Small object.
So output is
small destructed
small destructed
small destructed
There's another post that mentions this.
Anand.
|
|
|
|
|
Anand Krishnamoorthi wrote: The 2nd assignment fails to call the destructor of the Small object.
So output is
small destructed
small destructed
small destructed
From what I'm seeing, it's the expected output.
<br />
<br />
int main()<br />
{<br />
cdiggins::any a;
a = Small();
a = Small();
}<br />
<br />
I'm sure you are refering to the leak the some other people are talking about, but it's corrected since a long time now.
|
|
|
|
|
Hi,
I'm trying to use the example in the article with VC6 and get the following compile error. I'm using latest version from pablo_mag.
any a = 42;
int n = a.cast<int>();
int m = any_cast<int>(a);
I'm a Boost fan, but in this particular case I'd prefer not to have to use it.
Any suggestions?
Neville Franks, Author of Surfulater www.surfulater.com "Save what you Surf" and ED for Windows www.getsoft.com
|
|
|
|
|
Unfortunately, VC6 doesn't support that syntax for calling member templates.
The closest one can get is something like the following:
<br />
any a = 42;<br />
int n = a.cast_(any::to<int>());<br />
int m = any_cast<int>(a);<br />
But that's obviously not as nice looking as cast<int>() would be.
Do you think it worth adding this?
Pablo Aguilar
pablo dot aguilar at gmail dot com
|
|
|
|
|