C++ make::shared wrapping on existing raw pointer - c++

I am working on a small wrapper for an FMOD library. Below is a snippet of the code that I have, and there are other libraries that manage the SoundData class:
class SoundData
{
public:
...
std::string mSoundName;
std::shared_ptr<FMOD::Sound> mFmodSoundHandle;
...
}
void SoundLib::CreateSound(SoundData& data)
{
FMOD::Sound *sound = nullptr;
system->createSound(data.mSoundName.data(), FMOD_DEFAULT, nullptr, &sound);
data.mFmodSoundHandle = std::make_shared<FMOD::Sound>(sound);
}
Trying to compile this snippet of the code, I get this error:
Error C2664 'FMOD::Sound::Sound(const FMOD::Sound &)': cannot convert argument 1 from 'FMOD::Sound *' to 'const FMOD::Sound &' SoundLib ...\MSVC\14.29.30133\include\xutility 158
I cannot quite understand if I am using std::make_shared() in the wrong way here? The goal here is to save the output from createSound() that is passed as a sound variable into the structure SoundData. Variable data will be managed afterwards.

You're passing a pointer where you should pass a reference. Try *sound.
Notice that you're not wrapping a pointer, you're creating a new instance of Sound and copying the value of *sound into it.
To wrap it consider:
data.mFmodSoundHandle.reset(sound);

Related

Error C2664 'void IVerify::SetParams(void)': cannot convert argument 1 from 'std::wstring' to 'wchar_t *'

When I am calling SetParams function from the below function, it is throwing an error "cannot convert argument 1 from 'std::wstring' to 'wchar_t *'"
Can anyone please help me on this?
int main()
{
IVerify* pReader = new BCReader();
std::wstring oemPathKey;
pReader->SetParams(oemPathKey, L"read");
delete pReader;
return 0;
}
void BCReader::SetParams(wchar_t* wszParams, wchar_t* wszParamType)
{
m_wszParamType = wszParamType;
m_wszParams = wszParams;
}
The member variables are declared like as shown below:
class IVerify
{
private:
wchar_t* m_wszParams;
wchar_t* m_wszParamType;
};
There are two parts of the right answer:
1. You need to use pReader->SetParams(oemPathKey.c_str(), L"read");
2. Your approach is not safe, you trying to keep pointer to string in the class members.
But if the original string will go out of scope then you will receive Access Vioalation, if you are lucky :). So in SetParams you need to copy source string to the class members uisng for example wscpy (I recommend something like wscpy_s), also you need correctly handle allocation/deallocation for string copy.

long^ to LONG* conversion in C++/CLI

I have a DLL which I need to write a wrapper for. The goal is to use it in a C# .NET application so I need to use C++/CLI (never had read about it before, so I'm new to that).
The function header in the dll is the following:
extern "C" __declspec(dllexport) BOOL __stdcall PlayM4_GetPort(LONG* nPort);
The header I've defined in my wrapper is this:
bool PlayM4Wrapper::GetPort(long^ nPort);
From what I've understood, the circunflex sign (^) means that is a pointer to the argument (nPort). So what I'm trying to write is the following code but I'm getting a conversion error Error C2664 'BOOL (LONG *)': el argumento 1 no puede convertirse de 'System::Int32 ^' a 'LONG *' .
bool PlayM4Wrapper::GetPort(long^ nPort)
{
BOOL ret =_mLoader->m_PlayM4GetPort(nPort);
return static_cast<BOOL>(ret);
}
Can anyone please help me with this? How should I write this wrapper function?
Thanks.
From what I've understood, the circunflex sign (^) means that is a pointer to the argument
Not in the C++ understanding of a pointer. Yes, it is a reference to an instance of an object. But this reference is nothing you can use in C++. It's not a pointer and you cannot use it as a pointer. First, a long in .NET is not a reference type, so you don't need that. But from your method signature I guess that it is used as a hidden return value, so you need to write to it and therefor indeed need a reference. Since it's not a reference type in .NET, you will need another modifier to make it possible to pass the value back:
// equivalent C# signature:
// bool GetPort(ref long nPort)
bool PlayM4Wrapper::GetPort(long% nPort)
{
LONG local = nPort;
if(_mLoader->m_PlayM4GetPort(&local))
{
nPort = local;
return true;
}
return false;
}
Aparently, the % is called a tracking reference.

Creating an auto_ptr with 2 arguments

Hi I have a compile error when I run this code:
std::auto_ptr<MyDisplay> m_display =
std::auto_ptr<MyDisplay>(new MyDisplay(this, m_displayController));
The error is this one:
error C2664: 'MyDisplay::MyDisplay(DemoWindow *,DisplayController*)':
cannot convert parameter 2 from 'std::auto_ptr<_Ty>' to 'DisplayController*'
However when I pass only one argument the code is correct:
std::auto_ptr<DisplayController> m_displayController =
std::auto_ptr<DisplayController>(US_NEW(DisplayController, this));
What is the proper way to create the pointer in the auto_ptr with 2 arguments?
From the error message, it appears that m_displayController is an std::auto_ptr<DisplayController>, while the MyDisplay constructor expects a DisplayController*.
Try :
std::auto_ptr<MyDisplay> m_display =
std::auto_ptr<MyDisplay>(new MyDisplay(this, m_displayController.get()));
or better yet, make the constructor compatible with std::auto_ptr<DisplayController>.
As an aside : the choice of std::auto_ptr here is probably not the best. You might want to read up on the different types of smart pointers, and the different behaviors they have.
I'd like to clarify your idea of creating the auto pointer, which I hope will help.
Your goal here is to create an auto_ptr holding a DisplayController*. You could write
m_displayController = std::auto_ptr<DisplayController>( new DisplayController(x, y) );
Or have a function that returns a pointer, like this :
m_displayController = std::auto_ptr<DisplayController>( US_NEW(x,y) );
You can check out a simple example here.

Boost FOR_EACH Over A Ptr_Vector?

I'm currently having fun trying to learn some of the Boost libary. I'm currently doing what I guess will be a future homework project (semester hasn't started yet). However, this question is not about the homework problem, but about Boost.
Code:
/* AuctionApplication.h */
class AuctionApplication : boost::noncopyable
{
private:
boost::ptr_vector<Auction> auctions_;
boost::ptr_vector<Bidder> bidders_;
boost::ptr_vector<Bid> bids_;
/* AuctionApplication.cpp */
Bid *AuctionApplication::GetLatestBid(const Auction *auction)
{
Bid *highestBid = 0;
BOOST_FOREACH(Bid *bid, bids_) // Error here!
if (bid->GetAuction()->GetName() == auction->GetName())
highestBid = bid;
BOOST_FOREACH use to work with normal vectors with the exact same code as above. Since I've started using ptr_vectors I get the error:
error C2440: '=' : cannot convert from 'Bid' to 'Bid *'
Leading me to believe that ptr_vector somehow obscures the pointer from the foreach method.
If I instead write
BOOST_FOREACH(Bid *bid, bids_)
I get four errors of the type
error C2819: type 'Bid' does not have an overloaded member 'operator ->'
which sucks, because I know bid is a pointer.
How can I make BOOST_FOREACH iterate properly over the ptr_vectors?
ptr_vector takes ownership of heap allocated objects and presents each object as a reference so you don't need dereferencing and you use . instead of -> to access member variables/functions. e.g.
Bid highestBid = 0;
BOOST_FOREACH (Bid& bid, bids_)
if (bid.GetAuction()->GetName() == auction->GetName())
highestBid = &bid;

issue returning CArray

I am trying to return a CArray from a function and trying to call the function from another class
short ListMaker::RetArray(CString szName, CArray<CString, CString&> &szarr_Names) {
szarr_Names.Add(szName);
return 0;
}
int main() {
//..
CArray<CString, CString&> myArray;
ListMaker LM;
short nCode = LM.RetArray(L"Name", myArray);
//..
}
I am getting following errors:
Error 1 error C2664: 'RetArray' : cannot convert parameter 2 from 'CArray<TYPE,ARG_TYPE>' to 'CArray<TYPE,ARG_TYPE>'
Error 2 error C2511: 'short RetArray(CString,CArray<TYPE,ARG_TYPE> &)' : overloaded member function not found in 'ListMaker'
Please tell me the correct way to define and access the return value of the CArray.
Erm, frist of all if RetArray is a member of ListMaker class and you call it from main(), you cannot call it like this: short nCode = RetArray(L"Name", myArray);
If RetArray is a static member, use short nCode = ListMaker::RetArray(L"Name", myArray);. It it's non-static, use instance, short nCode = listMakerInstance.RetArray(L"Name", myArray);.
Check your header file for RetArray declaration in ListMaker class. It might differ from the implementation in your cpp file, hence you get the C2511 error.
You cannot store a reference in an array type, and CArray is to be absolutely avoided at all costs as it uses memcpy to resize and not copy construction, breaking your code the instant you need something with a useful constructor.
I think the problem is in CString&, try using CArray<CString, LPCTSTR> instead.