Im trying to create a PxFoundation and save it in my member variable "foundation" which is a std::shared_ptr. However upon creating the object I get this:
C2440: '<function-style-cast>': cannot convert from 'physx::PxFoundation *' to 'std::shared_ptr<physx::PxFoundation>'
How can I put the raw pointer from the PxCreateFoundation function into a shared_ptr? as I'm not calling the ctor of any PhysX class I cannot use std::make_shared, so using the normal std::shared_ptr<>() constructor seems my only option?
Code:
#include <memory>
#include <PxPhysics.h>
#include "PhysXErrorCallback.hpp"
#include "PhysXDefaultAllocator.hpp"
#include <foundation/PxFoundationVersion.h>
class PhysicsEngine
{
public:
PhysicsEngine();
std::shared_ptr<physx::PxFoundation> foundation;
static PhysXErrorCallback gDefaultErrorCallback;
static PhysXDefaultAllocator gDefaultAllocatorCallback;
};
PhysicsEngine::PhysicsEngine()
{
foundation = std::shared_ptr<physx::PxFoundation>(PxCreateFoundation(PX_FOUNDATION_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback));
}
EDIT:
After chaning the
foundation = std::shared_ptr<physx::PxFoundation>(...)
to
foundation.reset(...)
it now gives me these errors:
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\memory(1519): error C2440: '<function-style-cast>': cannot convert from 'physx::PxFoundation *' to 'std::shared_ptr<physx::PxFoundation>'
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\memory(1519): note: No constructor could take the source type, or constructor overload resolution was ambiguous
1>physicsengine.cpp(25): note: see reference to function template instantiation 'void std::shared_ptr<physx::PxFoundation>::reset<physx::PxFoundation>(_Ux *)' being compiled
1> with
1> [
1> _Ux=physx::PxFoundation
1> ]
1>physicsengine.cpp(25): note: see reference to function template instantiation 'void std::shared_ptr<physx::PxFoundation>::reset<physx::PxFoundation>(_Ux *)' being compiled
1> with
1> [
1> _Ux=physx::PxFoundation
1> ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\memory(1519): error C2228: left of '.swap' must have class/struct/union
EDIT2:
Heres the PxCreateFoundation declaration and definition:
PX_C_EXPORT PX_FOUNDATION_API physx::PxFoundation* PX_CALL_CONV
PxCreateFoundation(physx::PxU32 version, physx::PxAllocatorCallback& allocator, physx::PxErrorCallback& errorCallback);
physx::PxFoundation* PxCreateFoundation(physx::PxU32 version, physx::PxAllocatorCallback& allocator,
physx::PxErrorCallback& errorCallback)
{
return physx::shdfnd::Foundation::createInstance(version, errorCallback, allocator);
}
PxFoundation class:
/**
\brief Foundation SDK singleton class.
You need to have an instance of this class to instance the higher level SDKs.
*/
class PX_FOUNDATION_API PxFoundation
{
public:
virtual void release() = 0;
protected:
virtual ~PxFoundation()
{
}
};
createInstance definition:
Foundation* Foundation::createInstance(PxU32 version, PxErrorCallback& errc, PxAllocatorCallback& alloc)
{
//...
mInstance = reinterpret_cast<Foundation*>(alloc.allocate(sizeof(Foundation), "Foundation", __FILE__, __LINE__));
if(mInstance)
{
PX_PLACEMENT_NEW(mInstance, Foundation)(errc, alloc);
return mInstance;
}
//...
}
Seems like I found the error:
Most destructors in PhysX SDK are not public. Therefore trying to create a smart pointer with one of these classes results in an error.
Only other option beside using a raw pointer would be to create a custom deleter:
auto foundation = std::shared_ptr<physx::PxFoundation>(PxCreateFoundation(PX_FOUNDATION_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback), [=](physx::PxFoundation* f)
{
f->release();
});
Your foundation = line isn't actually calling a constructor. It's trying to cast the raw pointer to a shared_ptr using the syntax called a "functional cast" or "function-style cast" (#2 here), and then assign the result to the foundation variable (which has already been default-constructed). That won't work because shared_ptr has no cast from a raw pointer (to prevent it from accidentally taking ownership of things it shouldn't).
The best way to fix the problem is to use your constructor's initializer list to actually initialize foundation with the pointer:
PhysicsEngine::PhysicsEngine() :
foundation(PxCreateFoundation(PX_FOUNDATION_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback))
{
// empty
}
This passes the pointer to foundation's constructor, as opposed to letting foundation be default-constructed and then assigning to it afterward in the constructor body. But if you really need to do it by assignment for some reason, you can use the reset function to tell foundation to take ownership of the pointer:
PhysicsEngine::PhysicsEngine()
{
foundation.reset(PxCreateFoundation(PX_FOUNDATION_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback));
}
Related
Wanting to investigate the performance hit (if any) of std:function.
I have this struct:
struct InstructionDescription
{
std::string name;
word mask;
word code;
std::function<void(Cpu*, word)> func;
word flags;
};
and I set up a vector of them like this
std::vector<InstructionDescription> instructions_{
{
{"clr", DD_MASK, 0005000, &Cpu::Clr},
{"clrb", DD_MASK, 0105000, &Cpu::Clr},
{"com", DD_MASK, 0005100, &Cpu::Com},
.....
Works fine. Now if I change the struct to use a function pointer:
using InstrFunc = void(*)(Cpu*, word);
struct InstructionDescription
{
std::string name;
word mask;
word code;
InstrFunc func;
word flags;
};
which as far as I can see should be equivalent. And yet I get
1>C:\work\pdp\mysim\mysim\instructions.h(60,50): error C2664: 'std::vector<Cpu::InstructionDescription,std::allocator<Cpu::InstructionDescription>>::vector(std::initializer_list<_Ty>,const _Alloc &)': cannot convert argument 1 from 'initializer list' to 'std::initializer_list<_Ty>'
1> with
1> [
1> _Ty=Cpu::InstructionDescription,
1> _Alloc=std::allocator<Cpu::InstructionDescription>
1> ]
1> and
1> [
1> _Ty=Cpu::InstructionDescription
1> ]
1>C:\work\pdp\mysim\mysim\instructions.h(60,50): message : Element '1': no conversion from 'initializer list' to '_Ty'
1> with
1> [
1> _Ty=Cpu::InstructionDescription
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\include\vector(512,5): message : see declaration of 'std::vector<Cpu::InstructionDescription,std::allocator<Cpu::InstructionDescription>>::vector'
1>Console.cpp
VS2019. VS GUI is also highlighting the std::vector line saying 'InstructionDescription' is unknown and that the function names are not accessible (&Cpu::Clr for example)
The Cpu class is defined like:
struct Cpu {
void Clr(word) {};
void Com(word) {};
};
What am I doing wrong?
The std::function is very convenient: it recognizes that &Cpu::Clr is a member function whose first parameter will be a Cpu*.
When you make it a function pointer, this doesn't work like this. You have to use a member function pointer:
using InstrFunc = void (Cpu::*)(word);
Additional info
This is standard: std::function nicely copes with pointers to member functions by adding a pointer to the class as first argument. Of course, when you call it, you have to provide that additional parameter:
Cpu cpu;
for (auto& i:instructions_) {
i.func(&cpu, i.code); // as simple as that with std::function
}
When you go for the pointer to member function, it's less convenient:
Cpu cpu;
for (auto& i:instructions) {
(cpu.*i.func)(i.code);
}
Online demo (you need to comment/ comment out the specific lines)
I know I could do this better with std::vector, but the application I am messing with, has already a bunch of CArray parameters on a lot of related functions ... and I will not change them all at the moment!
I simply want to define an empty CArray<CClass*> — array of pointers to CClass, so the problem can not be on the CClass constructor — as the default value of a function parameter.
Approach 1
If I try to do it with assignment operator and default constructor:
void Function(CArray<CClass*> parameter = CArray<CClass*>());
I get the error:
1>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\include\afxTempl.h(262): error C2248: 'CObject::CObject' : cannot access private member declared in class 'CObject'
1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\include\afx.h(535) : see declaration of 'CObject::CObject'
1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\include\afx.h(510) : see declaration of 'CObject'
1> This diagnostic occurred in the compiler generated function 'CArray<TYPE>::CArray(const CArray<TYPE> &)'
1> with
1> [
1> TYPE=CClass *
1> ]
Approach 2
I also tried with a copy constructor:
void Function(CArray<Class*> parameter(CArray<CClass*>()));
I got the errors:
>File.cpp(line X): error C2664: 'FunctionClass::Function' : cannot convert parameter 1 from 'CArray<TYPE>' to 'CArray<TYPE> (__cdecl *)(CArray<TYPE> (__cdecl *)(void))'
1> with
1> [
1> TYPE=CClass*
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
line X: contains a call supplying the parameter to Function, as shown: pFunctionClass->Function(parameter);
1>CFunctionClass.cpp(line Y): error C2511: 'void CFunctionClass::Function(CArray)' : overloaded member function not found in 'CShoePlaceDoc'
1> with
1> [
1> TYPE=CClass*
1> ]
1> FunctionClass.h(line A) : see declaration of 'CFunctionClass'
line Y contains the Function implementation header, as shown: `void CFunctionClass::Function(CArray parameter)
1>File.cpp(line Z): error C2660: 'CClassFunction::Function' : function does not take 0 arguments
line Z: contains a call to Functionwithout supplying it parameters, as shown: pClassFunction->Function();
The approach didn't work, but it got its way towards a conclusion: It is not possible to use a copy-constructor for assigning a default value for a function parameter.
Approach 3
And if I try with a lambda:
void Function(CArray<CClass*> parameter = [] () -> CArray<CClass*>{ return CArray<CClass*> (); } );
, then I will get multiple outputs of these two errors:
1>FunctionClass.h(line A): error C2440: 'default argument' : cannot convert from '`anonymous-namespace'::<lambda2>' to 'CArray<TYPE>'
1> with
1> [
1> TYPE=CClass*
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>FunctionClass.h(line B): fatal error C1903: unable to recover from previous error(s); stopping compilation
line A: method declaration
line B: closing } of FunctionClass class that contains Function method
Origin of the problem
The root cause of the problem seems to be the fact that CArray is a class directly derived from CObject, which declares the assignment operator as private:
class AFX_NOVTABLE CObject
{
//...
private:
CObject(const CObject& objectSrc); // no implementation
void operator=(const CObject& objectSrc); // no implementation
//...
}
So, how can I supply an empty array as default value for the parameter?
With this declaration
void Function(CArray<CClass*> parameter /*...*/);
You can't. Calling this function will invoke the private copy constructor of CObject as you have noticed.
What you could do, is to add a object of static CArray<CClass*> in your class and initialize the function with a reference to it. This way it will be empty (as long as you do not populate it...) and you can perform a .IsEmpty() check on it.
private:
static CArray<CClass*> myObj;
//...
void Function(CArray<CClass*> ¶meter = myObj);
Or initialize it to 0. This way you simply check it by if (parameter) or if (NULL == parameter).
void Function(CArray<CClass*> *parameter = NULL);
I'm have a problem with *passing a deleter functor into a std::smart_ptr*. This is the first time I've tried anything like this, so I may be overlooking something very simple..
Here's what my functor class looks like;
#pragma once;
#ifndef ASSETDELETERS_H
#define ASSETDELETERS_H
#include "RenderSystem.h"
struct SourceImageDeleter
{
RenderSystem & refGraphicsRenderer;
unsigned int * ptrTextureID;
explicit SourceImageDeleter( RenderSystem & tempRef, unsigned int * tempPtrID )
: refGraphicsRenderer( tempRef ) ,
ptrTextureID(tempPtrID) {};
SourceImageDeleter( const SourceImageDeleter & originalCopy )
: refGraphicsRenderer( originalCopy.refGraphicsRenderer ) ,
ptrTextureID( originalCopy.ptrTextureID ) {};
void operator() ()
{
refGraphicsRenderer.deregisterTexture( ptrTextureID );
}
};
#endif
The RenderSystem::deregisterTexture function only requires one argument (unsigned int *), because of that, it's being passed at the creation of the functor. I've looked into the use of std::bind, but I don't have much experience with that and wasn't able to have much success using it instead of making a functor.
And here's the only method that uses it so far..
std::shared_ptr<SourceImage> Engine::createSourceImage( std::string tempFilepath )
{
SourceImage * tempImagePtr = new SourceImage( tempFilepath );
registerTexture( &tempImagePtr->textureID, &tempImagePtr->image );
return std::shared_ptr<SourceImage>( tempImagePtr , SourceImageDeleter( this->graphicsRenderer, &tempImagePtr->textureID ) );
}
I'm not sure why it's not working! I've basically been trying to have my smart_ptr run a custom deletion function all week, and between trying to figure out how pointers-to-method passing works, how std::bind/std::mem_fun_ref works, and how functors work has been stumping me all week..
Anyway, here's the compile error that Visual Studio has been giving me, I hope someone can help me figure out what I've been screwing up;
error C2064: term does not evaluate to a function taking 1 arguments
1> class does not define an 'operator()' or a user defined conversion operator to a pointer-to-function or reference-to-function that takes appropriate number of arguments
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\memory(1438) : see reference to function template instantiation 'void std::tr1::shared_ptr<_Ty>::_Resetp<_Ux,_Dx>(_Ux *,_Dx)' being compiled
1> with
1> [
1> _Ty=SourceImage,
1> _Ux=SourceImage,
1> _Dx=SourceImageDeleter
1> ]
1> c:\projects\source\engine.cpp(151) : see reference to function template instantiation 'std::tr1::shared_ptr<_Ty>::shared_ptr<SourceImage,SourceImageDeleter>(_Ux *,_Dx)' being compiled
1> with
1> [
1> _Ty=SourceImage,
1> _Ux=SourceImage,
1> _Dx=SourceImageDeleter
1> ]
(By the way, engine.cpp(151) is the return line inside Engine::createSourceImage shown above.. If I remove the deleter argument, the program compiles and runs fine aside from the obvious resource leaks associated with improper image deletion..)
std::shared_ptr passes in the pointer being deleted to the deleter, which is exactly what your error message says: the class does not define an operator() with the correct number of arguments.
Your deleter isn't expecting any parameters, so it won't work; you'll need to change it to void operator()(SourceImage*)
Maybe someone can help me understand the error.
I write this code:
class Text
{
private:
struct paragraph
{
vector<string> lines;
};
vector<shared_ptr<paragraph>> paragraphs;
public:
Text()
{
paragraphs.push_back(shared_ptr<paragraph>(new paragraph()));
}
};
int main()
{
shared_ptr<Text> pText(nullptr);
Text text();
pText.reset(&text);
return 0;
}
When I try to run it
I got this error:
1>c:\program files\microsoft visual studio 10.0\vc\include\memory(1664): error C2541: 'delete' : cannot delete objects that are not pointers
1> c:\program files\microsoft visual studio 10.0\vc\include\memory(1431) : see reference to function template instantiation 'void std::tr1::shared_ptr<_Ty>::_Resetp<_Ux>(_Ux (__cdecl *))' being compiled
1> with
1> [
1> _Ty=Text,
1> _Ux=Text (void)
1> ]
1> c:\program files\microsoft visual studio 10.0\vc\include\memory(1607) : see reference to function template instantiation 'std::tr1::shared_ptr<_Ty>::shared_ptr<_Ux>(_Ux (__cdecl *))' being compiled
1> with
1> [
1> _Ty=Text,
1> _Ux=Text (void)
1> ]
1> c:\documents and settings\owner\שולחן העבודה\e\class.cpp(29) : see reference to function template instantiation 'void std::tr1::shared_ptr<_Ty>::reset<Text(void)>(_Ux (__cdecl *))' being compiled
1> with
1> [
1> _Ty=Text,
1> _Ux=Text (void)
1> ]
What is meant "cannot delete objects that are not pointers"?
I'm not trying to delete any object.
In addition to the most vexing parse, your code contains a fundamental flaw:
You must not assign a pointer to a stack-allocated object to a shared_ptr.
This code will cause undefined behaviour which in practice means lots of pain:
shared_ptr<Text> pText(nullptr);
Text text;
pText.reset(&text);
shared_ptr will try to delete &text at the end of its lifetime.
The line Text text(); does not do what you think it does.
It parses it as the declaration of a function named text which accepts no argument and returns a value of type Text.
This is the reason why your line pText.reset(&text); does not compile.
However, you really do not want that line to compile: you are associating a shared_ptr object to a value with automatic storage duration: when the shared_ptr will go out of scope, it will try to delete that object, resulting in Undefined Behavior (most likely a crash in this case).
You main function should read.
int main()
{
shared_ptr<Text> pText(new Text);
return 0;
}
You had 2 problems. First, Text text() was being parsed as a function declaration. Second, you were passing the address of a stack variable to a shared_ptr, which will delete the object when the reference count reaches 0.
You should also consider whether you need to use a shared_ptr. Will you ever be sharing this pointer with any body else, or do you simply want to ensure it is destructed properly? You could consider unique_ptr in the latter case. Do you even need a pointer at all, could you just allocate the object on the stack?
I have defined the following CComPtr object and method in my class:
private:
CComPtr<IRawPdu>& getRawPdu();
// Returns the RawPdu interface pointer from the mRawPdu data member.
// mRawPdu is initialized, if necessary.
CComPtr<IRawPdu> mRawPdu;
// Initialized to 0 in the ctor. Uses lazy evaluation via getRawPdu().
In the constructor of my class, I initialise mRawPdu to 0 via the initialisor list. The getRawPdu() method used lazy evaluation if mRawPdu has yet to be initialised.
When compiling the code, I get the following errors:
Compiling...
topport.cpp
C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include\atlcomcli.h(295) : error C2664: 'ATL::AtlComPtrAssign' : cannot convert parameter 2 from 'const ATL::CComPtr<T>' to 'IUnknown *'
with
[
T=IRawPdu
]
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include\atlcomcli.h(292) : while compiling class template member function 'IRawPdu *ATL::CComPtr<T>::operator =(const ATL::CComPtr<T> &) throw()'
with
[
T=IRawPdu
]
sessionutilities.h(186) : see reference to class template instantiation 'ATL::CComPtr<T>' being compiled
with
[
T=IRawPdu
]
topglobals.cpp
C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include\atlcomcli.h(295) : error C2664: 'ATL::AtlComPtrAssign' : cannot convert parameter 2 from 'const ATL::CComPtr<T>' to 'IUnknown *'
with
[
T=IRawPdu
]
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include\atlcomcli.h(292) : while compiling class template member function 'IRawPdu *ATL::CComPtr<T>::operator =(const ATL::CComPtr<T> &) throw()'
with
[
T=IRawPdu
]
sessionutilities.h(186) : see reference to class template instantiation 'ATL::CComPtr<T>' being compiled
with
[
T=IRawPdu
]
Any suggestions as to what could be causing this?
Based on the error given by the compiler it appears that it cannot infer a conversion between IRawPdu and IUnknown.
Does it actually inherit from IUnknown? If so then it's possibly an include ordering issue. Can you give more insight into the hierarchy of IRawPdu
Don't pass CComPtr<>'s around since there's no need, just return the pointer to the interface. For example:
IRawPdu* getRawPdu() { return mRawPdu; } // Does not add to the reference count
HRESULT get_RawPdu(IRawPdu** ppPdu) // Returns RawPdu, but add ref's it.
{
return mRawPdu.CopyTo(ppPdu);
}
CComPtr<IRawPdu> mRawPdu;
// Initialized to 0 in the ctor. Uses lazy evaluation via getRawPdu().
So, when it comes time to use it:
IRawPdu* pTempRawPdu = class->getRawPdu();
// use pTempRawPdu in a temporary manner (since it's not add reffed)
But, better would be:
CComPtr<IRawPdu> spRawPdu = class->getRawPdu();
// the ctor of the local CComPtr<> calls AddRef() (and automagically Release's when done)