I am trying to replace Poco::AutoPtr with some alternative in boost. Here is what I have discovered so far:
What I have: below classess are being used with Poco::AutoPtr. They need to implement reference counted method with implementing duplicate() and release() methods.
I am using above referece_counted.h and Poco::AutoPtr in a complex class hierarchy with multiple inheritance and c++ diamond problems.
A simplified version of classes would look something like this
class A : virtual public ReferenceCounted
{
...
}
class B : public A
{
...
}
class C : public A
{
...
}
class D : public A, B
{
...
}
and the list goes on for few more level deep. I know that this needs to be refactored with a simplified hierarchy but I wanna remove Poco::AutoPtr first with proper replacement in boost:
What I have found so far:
I have found that boost::intrusive_ptr is the closest smart pointer that can be a good replacement of Poco::AutoPtr.
I am however not able to implement the proper solution with this because the intrusive_ptr requires intrusive_ptr_add_ref and intrusive_ptr_release methods created specifically for each class with which I need to use the pointer. I tried using templates but still not having proper solution at hand.
Also one more issue is that I need to typecast from base to derived class many times.
is intrusive_ptr is the correct smart pointer for this usage ? and if yes.. can anybody give me suggestion regarding how to use the same ?
I am however not able to implement the proper solution with this
because the intrusive_ptr requires intrusive_ptr_add_ref and
intrusive_ptr_release methods created specifically for each class with
which I need to use the pointer.
No-no. It is should not be hard. As Boost documentation says:
On compilers that support argument-dependent lookup,
intrusive_ptr_add_ref and intrusive_ptr_release should be defined in
the namespace that corresponds to their parameter; otherwise, the
definitions need to go in namespace boost.
Try this: main.cpp (built ok with "g++ main.cpp -o main -lboost_system")
#include <boost/intrusive_ptr.hpp>
class MyObject
{
public:
void duplicate(){
// ...
}
void release(){
// ...
}
};
namespace boost {
template <class T>
void intrusive_ptr_add_ref( T * po ) {
po->duplicate(); // your internal realization
}
template <class T>
void intrusive_ptr_release( T * po ) {
po->release();
}
}
int main(int argc, char **argv)
{
// ...
boost::intrusive_ptr<MyObject> ptr( new MyObject );
boost::intrusive_ptr<MyObject> ptr2 = ptr; // should work
}
Related
I am aware of the lack of reflection and basic template mechanics in C++ so the example below can't work. But maybe there's a hack to achieve the intended purpose in another way?
template <typename OwnerClass>
struct Template
{
OwnerClass *owner;
};
struct Base
{
virtual void funct ()
{
Template <decltype(*this)> temp;
// ...
}
};
struct Derived : public Base
{
void whatever ()
{
// supposed to infer this class and use Template<Derived>
// any chance some macro or constexpr magic could help?
funct();
}
};
In the example, Derived::whatever() calls virtual method Base::funct() and wants it to pass its own class name (Derived) to a template. The compiler complains "'owner' declared as a pointer to a reference of type 'Base &'". Not only does decltype(*this) not provide a typename but a reference, the compiler also can't know in advance that funct is called from Derived, which would require funct() to be made a template.
If funct() was a template however, each derived class needs to pass its own name with every call, which is pretty verbose and redundant.
Is there any hack to get around this limitation and make calls to funct() infer the typename of the calling class? Maybe constexpr or macros to help the compiler infer the correct type and reduce verbosity in derived classes?
You should use CRTP Pattern (Curiously Recurring Template Pattern) for inheritance.
Define a base class:
struct CBase {
virtual ~CBase() {}
virtual void function() = 0;
};
Define a prepared to CRTP class:
template<typename T>
struct CBaseCrtp : public CBase {
virtual ~CBaseCrtp() {}
void function() override {
using DerivedType = T;
//do stuff
}
};
Inherit from the CRTP one:
struct Derived : public CBaseCrtp<Derived> {
};
It should work. The only way to know the Derived type is to give it to the base!
Currently, this can't be done. Base is a Base and nothing else at the time Template <decltype(*this)> is instantiated. You are trying to mix the static type system for an inheritance hierarchy inherently not resolved before runtime. This very same mechanism is the reason for not calling virtual member functions of an object during its construction.
At some point, this limitation might change in the future. One step towards this is demonstrated in the Deducing this proposal.
I hope I can explain myself.
Supose I have next:
File "A.h":
#include "C.h"
public class A{
// Some code...
}
File "B.h":
#include "A.h"
public class B{
A a = new A(); //With this line I mean I'm using one instance of "A" inside "B.h"
//Some code...
}
Is it possible to include "C.h" ONLY inside "A.h"?
My problem is that the code I've included is giving me a lot of conflicts with usual functions. It's not an option to correct conflicts one by one, because there is a huge set of them. Also, my "C.h" code included is only a test code: after some tests, I will delete the include line.
Is there any way of 'bubbling' my include?
Thank you in advance.
EDIT: A.h and B.h are on the same namespace.
Is it possible to include "C.h" ONLY inside "A.h"?
No. Not to my knowledge.
If you have name conflicts, just include C.h within an other namespace, as #user202729 proposed. This can help.
But I guess you use C in A for tests and you cannot use it in C in A without the implementation which is not compatible to C++Cli or content from B.h.
We used the pimpl ideom (pointer to implementation).
Example:
c++/clr currently does not allow do be included directly and that's why sometimes you cannot use libraries you want to use (like C.h), because they do rely on the support of .
This is my C.h ( used by all the other headers)
struct LockImpl; // forward declaration of C.
class C
{
public:
C();
virtual ~C();
public:
void Lock() const;
void Unlock() const;
LockImpl* _Lock;
};
This is my C.cpp (compiled without /clr )
#include <mutex>
struct LockImpl
{
std::mutex mutex;
};
C::C() : _Lock(new LockImpl()) {}
C::~C() { delete _Lock; }
void C::Lock() const
{
_Lock->mutex.lock();
}
void C::Unlock() const
{
_Lock->mutex.unlock();
}
A.h
#include "C.h"
public class A{
C c;
void someMethod()
{
c.Lock() // I used another template for a RAII pattern class.
c.Unlock()
}
}
We are trying to namespace the versions of our API with namespaces, although we figured that we will be getting some problems with virtual functions :
namespace v1 {
class someParam {
public:
someParam() {};
virtual ~someParam() {};
};
class someClass {
public:
someClass() {};
virtual ~someClass() {};
virtual bool doSomething(someParam a);
};
bool someClass::doSomething(someParam a)
{
return true;
}
}
namespace v2 {
class someParam : public v1::someParam {
public:
bool doParamStuff();
};
bool someParam::doParamStuff()
{
return true;
}
}
// Type Aliasing for v2 API
using someClass = v1::someClass;
using someParam = v2::someParam;
// SOME OTHER PROGRAM
class plugin : public someClass
{
public:
plugin() {};
virtual ~plugin() {};
bool doSomething(someParam a) override;
};
In this specific case, we are creating extension of existing classes to allow binary compatibility. Although, we get a compilation error for plugin::doSomething because of the override keyword as it is not overriding someClass::doSomething because:
plugin::doSomething(v2::someParam) vs someClass::doSomething(v1::someParam).
Is there any way to fix up the plugin without explicitely using v1 for someParam in plugin class ? Ideally, nothing should be done on the plugin side, and without having to create v2::someClass
This:
virtual bool doSomething(::v1::someParam a)
specifies a binary (and C++) interface. You cannot override it with
virtual bool doSomething(::v2::someParam a)
as that is a different type. They are not compatible. These signatures are unrelated.
When you update someParam, you must also update every interface that uses someParam, and then every interface that uses those interfaces, etc.
So, in namespace v2:
class someClass: ::v1::someClass {
public:
virtual bool doSomething(::v1::someParam a) override final;
virtual bool doSomething(someParam a);
};
and in doSomething(v1::someParam) describe how to generate a v2::someParam and pass it to the new doSomething.
If you cannot do this, you instead have to do this:
class someClass {
public:
virtual bool doSomething(someParam a);
};
and make v2::someClass a type unrelated to v1::someClass.
Regardless, you do
using someClass = v2::someClass;
Now, instead of using using declarations, you can instead conditually use inline namespaces.
When you update a version, make the current version the inline namespace. The others are normal namespaces.
Code will now silently start using the inline namespace that is "current".
You can import types from previous namespaces by using symbol = ::library_ns::v1::symbol; This should only be done when that type is unchanged, as well as all of its parameters.
Now, if your ::v2::someParam is only a helper, you can split someParamArg from someParamInstance types.
someParamArg would then be the argument type of the root of the someParam heirarchy (::v1::someParam), while someParamInstance would be ::v2::someParam; what people should create when they want to use it.
In this case, someParamArg needs to be able to consider every state of someParamInstance, even those from later versions. Hence this only works if ::v2::someParam is essentially a helper, or if it supports internal value-type polymorphism.
I know that additional initialization methods are evil, as they leave a very nasty option for having object half-constructed and as result all methods needs to check for this. But what about this situation?
class config;
class cfg_item final
{
private:
friend class config;
cfg_item(std::weak_ptr<config> owner) : owner(owner) { }
std::weak_ptr<config> owner;
}
class config final : private std::enable_shared_from_this<config>
{
public:
config()
{
items.emplace(std::make_shared<cfg_item>(weak_from_this())); // Will crash!
}
private:
std::vector<std::shared_ptr<cfg_item>> items;
}
int main(int argc, char * argv[])
{
std::shared_ptr<config> cfg = std::make_shared<config>();
}
I KNOW WHY IT CRASHES. The std::shared_ptr in the main is not yet initialized with shared pointer to config instance, so constructor does not know how to make weak_from_this and just raises std::bad_weak_ptr exception because there are no valid std::shared_ptr pointing to this at constructor's call time.
The question is: how can I avoided the whole thing? I believe the only way I see would be to add separate initialization method, which is evil as I've already mentioned...
As note about real code: the constructors loads cfg_item from external source. It is assumed that all cfg_items are available for the entire lifetime of config. The weak pointers back to config are mandatory, as cfg_item must push all changes done to it back to config to save to external source
If you look at the answers to this question, there are strong arguments why an external initialization function is necessary. However, you rightfully write
I know that additional initialization methods are evil, as they leave a very nasty option for having object half-constructed and as result all methods needs to check for this.
it's possible to reduce this problem. Say you have a class foo, with the protocol that each time a foo object is constructed, foo::init() needs to be called. Obviously, this is a brittle class (client code will eventually omit calls to init()).
So, one way is to make the (non-copy / non-move) constructors of foo private, and create a variadic static factory method that creates objects, then calls init():
#include <utility>
class foo {
private:
foo() {}
foo(int) {}
void init() {}
public:
template<typename ...Args>
static foo create(Args &&...args) {
foo f{std::forward<Args>(args)...};
f.init();
return f;
}
};
In the following code
template<typename ...Args>
static foo create(Args &&...args) {
foo f{std::forward<Args>(args)...};
f.init();
return f;
}
note that this single method can be used for all constructors, regardless of their signature. Furthermore, since it is static, it is external to the constructor, and doesn't have the problems in your question.
You can use it as follows:
int main() {
auto f0 = foo::create();
auto f1 = foo::create(2);
// Next line doesn't compile if uncommented
// foo f2;
}
Note that it's impossible to create an object without this method, and the interface doesn't even contain init.
I searched many pages, and I think I have known how to write the std::hash. But I don't know where to put it.
An example is presented here http://en.cppreference.com/w/cpp/utility/hash .
However, I defined my type Instance in namespace ca in file instance_management.h. I want to use unordered_set<Instance> in the same file in another class InstanceManager. So I write the following code:
namespace std
{
template <> struct hash<ca::Instance>
{
size_t operator()(const ca::Instance & instance) const
{
std::size_t seed = 0;
// Some hash value calculation here.
return seed;
}
};
} // namespace std
But where should I put it? I tried many locations but all failed.
I am using visual studio 2013. I tried to put the previous code in some locations but all failed to compile it.
// location 1
namespace ca
{
class Instance {...}
class InstanceManager
{
// ... some other things.
private unordered_set<Instance>;
}
}
// location 2
There are several ways.
Specializing std::hash
In your code make sure that your std::hash<Instance> specialization is preceded immediately by the Instance class definition, and followed by the use of the unordered_set container that uses it.
namespace ca
{
class Instance {...};
}
namespaces std {
template<> hash<Instance> { ... };
}
namespace ca {
class InstanceManager
{
// ... some other things.
private unordered_set<Instance>;
}
}
One drawback is that you can have funny name lookup interference when passing a std::hash<ca::Instance> to other functions. The reason is that the associated namespace (ca) of all the template arguments of std::hash can be used during name lookup (ADL). Such errors are a bit rare, but if they occur they can be hard to debug.
See this Q&A for more details.
Passing your hash to unordered_set
struct MyInstanceHash { ... };
using MyUnorderedSet = std:unordered_set<Instance, MyInstanceHash>;
Here, you simply pass your own hash function to the container and be done with it. The drawback is that you have to explicitly type your own container.
Using hash_append
Note, however, there is the N3980 Standard proposal is currently pending for review. This proposal features a much superior design that uses a universal hash function that takes an arbitrary byte stream to be hashed by its template parameter (the actual hashing algorithm)
template <class HashAlgorithm>
struct uhash
{
using result_type = typename HashAlgorithm::result_type;
template <class T>
result_type
operator()(T const& t) const noexcept
{
HashAlgorithm h;
using std::hash_append;
hash_append(h, t);
return static_cast<result_type>(h);
}
};
A user-defined class X then has to provide the proper hash_append through which it presents itself as a byte stream, ready to be hashed by the univeral hasher.
class X
{
std::tuple<short, unsigned char, unsigned char> date_;
std::vector<std::pair<int, int>> data_;
public:
// ...
friend bool operator==(X const& x, X const& y)
{
return std::tie(x.date_, x.data_) == std::tie(y.date_, y.data_);
}
// Hook into the system like this
template <class HashAlgorithm>
friend void hash_append(HashAlgorithm& h, X const& x) noexcept
{
using std::hash_append;
hash_append(h, x.date_);
hash_append(h, x.data_);
}
}
For more details, see the presentation by the author #HowardHinnant at CppCon14 (slides, video). Full source code by both the author and Bloomberg is available.
Do not specialise std::hash, instead write your own hash function object (see Edge_Hash below) and declare your unordered_set with two template arguments.
#include <unordered_set>
#include <functional>
namespace foo
{
// an edge is a link between two nodes
struct Edge
{
size_t src, dst;
};
// this is an example of symmetric hash (suitable for undirected graphs)
struct Edge_Hash
{
inline size_t operator() ( const Edge& e ) const
{
static std::hash<size_t> H;
return H(e.src) ^ H(e.dst);
}
};
// this keeps all edges in a set based on their hash value
struct Edge_Set
{
// I think this is what you're trying to do?
std::unordered_set<Edge,Edge_Hash> edges;
};
}
int main()
{
foo::Edge_Set e;
}
Related posts are, eg:
Inserting in unordered_set using custom hash function
Trouble creating custom hash function unordered_map
Thanks to everyone.
I have found the reason and solved the problem somehow: visual studio accepted the InstanceHash when I was defining instances_. Since I was changing the use of set to unordered_set, I forgot to specify InstanceHash when I tried to get the const_iterator, so this time the compiler tried to use the std::hash<> things and failed. But the compiler didn't locate the line using const_iterator, so I mistakenly thought it didn't accept InstanceHash when I was defining instances_.
I also tried to specialize the std::hash<> for class Instance. However, this specialization requires at least the declaration of class ca::Instance and some of its member functions to calculate the hash value. After this specialization, the definition of class ca::InstanceManage will use it.
I now generally put declarations and implementations of almost every classes and member functions together. So, the thing I need to do is probably to split the ca namespace scope to 2 parts and put the std{ template <> struct hash<ca::Instance>{...}} in the middle.