I'm writing a C++/CLI class that needs to hold on to CComPtr for the duration of its lifefime, e.g.
public ref class MyClass
{
public:
MyClass()
{
CComPtr<ISomeType> pSomeType;
// init someType;
m_pSomeType = pSomeType;
}
private:
CComPtr<ISomeType> m_pSomeType;
void DoSomething()
{
m_pSomeType->DoSomething();
}
}
However this doesn't compile as mixed types are not supported - the solution is to use an AutoPtr. I still need reference counting and so this is what I came up with.
public ref class MyClass
{
public:
MyClass()
{
CComPtr<ISomeType> pSomeType;
// init someType;
m_pSomeType = new CComPtr<ISomeType>(pSomeType);
}
private:
AutoPtr<CComPtr<ISomeType>> m_pSomeType;
void DoSomething()
{
CComPtr<ISomeType> pSomeType = *m_pSomeType.GetPointer();
pSomeType->DoSomething();
}
}
This looks nasty to me, and I also suspect that its wrong in some way (I come from a C# background so I'm kind of learning a lot of this as I go).
How should I "store" a CComPtr as a member of a C++/CLR class?
I've made a smart pointer that might help you. It can't be used to manage COM pointers directly, but it can be used to hold a CComPtr inside a managed class.
scoped_ptr for C++/CLI (ensure managed object properly frees owned native object)
Please respect the license requirements if you choose to use it (commercial use is not prohibited, but you must give credit).
Also, you can write
(*m_pSomeType)->DoSomething();
instead of copying the CComPtr (which has to update the reference count).
Besides that, I would use the ctor-initializer-list instead of assignment in the constructor.
MyClass()
: m_pSomeType(new CComPtr<ISomeType>)
{
}
If you want to compile managed and unmanaged code seperately then here is a link.
Using this you can retain flavour of both.
Related
In my program I need a factory function that provides instances of separate class because I need control over the details of each instance and to be aware of how many instances are in existence at a time. In particular returning a std::shared_ptr is ideal, but this is initially impossible due to a known issue with the "make" fucntions of the std::pointer types as they would need to be friends with my Widget class as well, which isn't portable since it relies on the current implementation of those methods that may change.
To get around this, I want to employ the Passkey idiom, which was directly recommend for this situation as described at the bottom of this: https://abseil.io/tips/134. I also based my implementation off the lessons learned here: https://arne-mertz.de/2016/10/passkey-idiom/
This is a sample project that uses my same setup as my full project:
#include <iostream>
class Widget
{
public:
class Key
{
friend class Factory;
private:
Key() {};
Key(const Key&) = default;
};
int mTest;
explicit Widget(Key, int test) { mTest = test; }
int getTestVar() { return mTest; }
};
class Factory
{
public:
int mTestPass;
Factory(int input) { mTestPass = input; }
std::shared_ptr<Widget> factoryMake() { return std::make_shared<Widget>(Widget::Key{}, mTestPass); }
};
int main()
{
Factory testFactory(10);
std::shared_ptr<Widget> testWidget = testFactory.factoryMake();
std::cout << testWidget->getTestVar();
return 0;
}
However, I get
Error C2248 'Widget::Key::Key': cannot access private member declared in class 'Widget::Key' TestProject ...\include\xmemory 204
This has me completely lost, since the error coming from xmemory.cpp indicates that std::make_shared is sill trying to access a private constructor. As far as I'm aware, the construction of the Key instance occurs within the factoryMake() function, which belongs to Factory, and then that instance is passed into the std::make_shared function; therefore, std::make_shared should not need access to the Key constructor since an already constructed instance is being passed to it, which is the entire point of using this idiom in this context. The class itself is public so it should have no issues interacting with the type Key, only the constructor should be inaccessible.
In the end I can just skip using std::make_shared and instead use the shared_ptr(*T) constructor with a raw pointer, but this is slightly less efficient due to the extra allocation it requires, as noted in my first link. It isn't a big deal as I'm not making many widgets but I'd ultimately prefer to get the more ideal implementation working.
What am I missing here?
The problem is that the compiler needs to copy your Widget::Key when you call std::make_shared, and you have declared the copy constructor private. You can solve this in one of two ways:
Make the copy constructor of Widget::Key public.
Change the Widget constructor to take the Widget::Key by const reference:
explicit Widget(const Key&, ...
EDIT:
/*
Is it possible to access the non JSAPI class object in javascript via JSAPI inherited envelop.
Some thing like below.
*/
class DataPersonal
{
public:
std::string GetName()
{
return "ABC";
}
};
class Envelop:FB::JSAPIAuto
{
public:
Envelop(){
registerMethod("GetData", make_method(this, &Envelop::GetData));
}
DataPersonal* GetData()
{
return new DataPersonal();
}
};
/*
In JavaScript
alert(plugin0.GetData().GetName());
Where plugin0 is Envelop
*/
The reason for this is the source code of DataPersonal is not available, It is in compiled form So I cant alter the DataPersonal class.
Any workaround for this?
I'm a little confused. What exactly makes you think that there would be a way to access members of a C++ object in Javascript without using registerMethod or registerProperty? There is a reason that the JSAPIAuto class exists, and that reason is to provide an interface between javascript and C++.
The only way to make "_name" accessible would be to use registerProperty and a getter/setter that get/set _name or registerMethod on a GetName and registerMethod on a SetName.
Perhaps I don't really understand your question or what you are trying to do?
if you registerProperty with a getter method and a setter method then from javascript you will use it like a normal member:
// In C++ in the constructor
registerProperty("_name", make_property(this, &MyClassAPI::get_name, &MyClassAPI::set_name));
// In the javascript
myPlugin._name = "Bobb";
alert(myPlugin._name);
Does that help at all? Javascript knows nothing about C++ or C++ types, so you can't directly expose a C++ class to it; it wouldn't be anything but an opaque pointer to javascript. Behind the scenes an NPObject* is created that wraps the JSAPI type and converts values and such to and from as needed, it's one of the reasons that FireBreath is so convenient to use.
EDIT: Your revised question makes more sense. Basically it might be possible to do what you describe by having the JSAPI object make_method with a pointer to the internal object and the function pointer to the method you want it to call, like so:
class DataPersonal
{
public:
std::string GetName()
{
return "ABC";
}
};
class Envelop : FB::JSAPIAuto
{
public:
Envelop() {
registerMethod("GetName", make_method(&m_data, &DataPersonal::GetName));
}
private:
DataPersonal m_data;
};
As you can see in the example, you cannot just return a pointer to a class and expect it to work -- it won't. If it did, we wouldn't need a complex class like JSAPI to wrap it to make it work. However, as far as I know there is no reason that make_method can't wrap a method from another class as long as the parameter and return types are all compatible with JSAPI. The trick is to make sure that the lifecycle of the pointer you use (in this case &m_data) is tied to your JSAPI class; otherwise you could have a case where the object has been freed but javascript still wants to use it.
You would of course need to register a property or method for each property or method on the inner class that you want to expose. If any of them had parameters or return types that are not compatible with JSAPI (which is likely, all things considered) you can just add a wrapper function on the JSAPI object that calls the function on the inner object. In short, you use the JSAPI class as a wrapper to the methods and object on the inside class.
JSAPI does about as much automatic conversion with arbitrary functions as is possible; it's not at all possible to just hand a random class type to javascript and have it understand.
I don't think you can do this, every your C++ object that you want to access from Javascript should be inherited from FB::JSAPIAuto, you can't just return a C++ pointer which won't work in Javascript.
you can use the following way to access other C++ objects and their methods or properties.
class MyJSAPIClass : public FB::JSAPIAuto
{
public:
MyJSAPIClass(const MyPluginPtr& plugin, const FB::BrowserHostPtr& host)
{
// Register your c++ object as a read only property
registerProperty("myCppObject",
make_property(this, &MyJSAPIClass ::GetMyCppMethod));
}
FB::JSAPIPtr GetMyCppMethod() { return m_cpp_object; }
private:
MyCPPClassPtr m_cpp_object;
}
FB_FORWARD_PTR(MyCPPClass)
class MyCPPClass : public FB::JSAPIAuto
{
public:
MyCPPClass()
{
_name="My name is...";
// Register your get name as a read only property
registerProperty("name",
make_property(this, &MyCPPClass::GetName));
}
std::String GetName()
{
return _name;
}
private:
std::string _name;
}
Then, in your Javascript code you can access your name form MyCPPClass as below,
plugin.myCppObject.name
I've been trying to come up with the best way to distribute a portion of my game code, but not all of it, in order to allow people to mod the game but not create standalone games using my code. This is how many games already work, such as Doom3 - before the GPL release, the SDK was only a portion of the code that would create a DLL for the unmodifiable EXE.
I successfully split up my code into an EXE/SDK for this purpose, but my concern is that the EXE references classes in the SDK. For one example, if I compile the EXE which has an array of objects of type Entity, Entity is declared in the SDK, and then I go and add another member variable to that class, compile the DLL, and then run the old EXE with the new DLL, wouldn't that mean that the EXE has incorrect information about the size of Entity?
Or am I over-thinking this?
There is a whole heap of problems with "if you modify this class it wont work with the class defined somewhere else.
There are also plenty of solutions to those problems.
Typically forming interfaces using (smart) pointers and/or references rather than the class itself avoids both parts of the code having to agree on the size of a class.
So, for example, instead of having :
class EntityCollection
{
private:
vector <Entity> entities;
public:
void addEntity(Entity e) { entities.push_back(e); }
void removeEntity(Entity e) { ... }
};
we'd use a pointer style storage (should really use smart pointers, but to make it short and simple, I'm not):
class EntityCollection
{
private:
vector <Entity*> entities;
public:
void addEntity(Entity* e) { entities.push_back(e); }
void removeEntity(Entity* e) { ... }
};
Now, it won't matter how large the entity is, or what it contains, it will still be "pointer sized" in the vector.
Another variant is to have a "pimpl" interface. You have a main class defintion, inside it is a (smart) pointer to an implementation class, which provides a known set of virtual functions.
Something like this:
class Entity
{
public:
class EntityImpl
{
virtual int func() = 0;
...
};
Entity(EntityImpl* impl) pImpl(impl) {}
...
int func() { return pImpl->func(); }
private:
EntityImpl* pImpl;
};
These are of course not your only possible concerns, but should give you some ideas of "here's something you use to solve the problem".
I have a ISceneNode interface and from that a SceneNode base class.
From the SceneNode class derive MeshNode, AnimNode, LightNode, CameraNode, ect...
Now I have an actor class that through a method takes in a shared_ptr
and stores it in a field.
What I'd like to be able to do is send in any std::shared_ptr or other derived classes into the function that takes in a shared_ptr .
With bare pointers this would be an implicit conversion.
The solution that I came up with was to write a overload for each of the derives and then cast it within the method using dynamic_pointer_cast . That's just nasty there should be a better way.
Is there a way to get implicit casting, or a better way I don't know of to handle this?
What's the proper way to handle this?
void SomeFunc()
{
std::shared_ptr<MeshNode> pMeshNode( new MeshNode() );
gActor.SetNode( pMeshNode ); // won't compile.
// or do i have to do it like this
gActor.SetNode( std::dynamic_pointer_cast<ISceneNode> (pMeshNode) );
}
void Actor::SetNode( std::shared_ptr<ISceneNode> pNode )
{
mpNode = pNode;
}
// or do I have to do it like this? Making an over load for each derived.
void Actor::SetNode( std::shared_ptr<MeshNode> pMeshNode )
{
mpNode = std::dynamic_pointer_cast<ISceneNode> (pMeshNode);
}
You claim it won't compile, but the following test compiles and runs for me (VS2012, Clang, G++). You should post the error you're getting, as it's most likely something else.
#include <memory>
struct IBase {};
struct Derived : IBase {};
void Foo(std::shared_ptr<IBase> p) {}
int main()
{
std::shared_ptr<Derived> d;
Foo(d);
}
I bet you are using VS2010? I found some problems with smart pointers support there? On a compiler with better C++11 support (eg. VS2012, gcc, clang) it should compile fine. However I would suggest you some extensions:
class Actor {
std::shared_ptr<ISceneNode> mpNode;
public:
void SetNode(std::shared_ptr<ISceneNode> pNode)
{ mpNode = std::move(pNode); }
};
void SomeFunc()
{
gActor.SetNode(std::make_shared<MeshNode>());
}
It is always better to allocate std::shared_ptr with std::make_shared<T>() which saves you one dynamic allocation and even up to the half of shared state memory overhead. You should also either pass std::shared_ptr as a reference to a function or at least move it to a new value like I did. You could also consider using std::unique_ptr which makes it even more effective (no shared state memory overhead and thread safe reference counting) and makes the design better (clear ownership). You can use in a very similar way:
class Actor {
std::unique_ptr<ISceneNode> mpNode;
public:
void SetNode(std::unique_ptr<ISceneNode> pNode)
{ mpNode = std::move(pNode); }
};
void SomeFunc()
{
gActor.SetNode(std::unique_ptr<MeshNode>(new MeshNode));
}
I had been doing dependency injection using raw pointers and I decided to convert my code to use shared_ptr. This works but I'm wondering if I could use unique_ptr instead? In my example below, MyClass would manage the lifetime of the credit card service.
class PaymentProcessor
{
PaymentProcessor(?? creditCardService):
:creditCardService_(creditCardService)
{
}
private:
CreditCardService *creditCardService_;
}
class MyClass
{
public:
void DoIt()
{
creditCardService_.reset(new VisaCardService());
PaymentProcessor pp(creditCardService_);
pp.ProcessPayment();
}
private:
std::unique_ptr<CreditCardService> creditCardService_;
}
Can you pass a unique_ptr to another class where the other class is just "using" the pointer (without owning it??)? If so is this a good idea and what should the type of the parameter be in the constructor for PaymentProcessor?
UPDATE
In the example as shown above I can alternatively create a VisaCardService variable on the stack and have the PaymentProcessor constructor take this as a reference parameter. This seems to be the recommended C++ practice. However, in the case where the concrete type of creditCardService_ is not known until runtime (e.g., the user chooses the particular Credit Card Service to use at runtime), is using std::unique_ptr with references the best solution?
Can you pass a unique_ptr to another class where the other class is
just "using" the pointer (without owning it??)?
In that case, change the pointer to reference :
class PaymentProcessor
{
public:
PaymentProcessor(CreditCardService & creditCardService_):
:creditCardService_(creditCardService_)
{
}
private:
CreditCardService &creditCardService_;
};
void DoIt()
{
creditCardService_.reset(new VisaCardService());
PaymentProcessor pp(*creditCardService_);
pp.ProcessPayment();
}
If you still want to use a pointer, then you need to use get method :
class PaymentProcessor
{
public:
PaymentProcessor(CreditCardService * creditCardService_):
:creditCardService_(creditCardService_)
{
}
private:
CreditCardService *creditCardService_;
};
void DoIt()
{
creditCardService_.reset(new VisaCardService());
PaymentProcessor pp(creditCardService_.get());
pp.ProcessPayment();
}