I'm having a question about when it is necessary to use SafeArrayAccessData to lock a SAFEARRAY, which is passed by managed code.
Here is our code. The VARIANT is passed by managed code, with a string array. During code review, somebody suggest to use SafeArrayAccessData/SafeArrayUnAccessData. But he is not sure about why and what's the benefit. Can you share some of your experiences? Thanks!
STDMETHODIMP Base::Method1(VARIANT values, VARIANT_BOOL result)
{
CComSafeArray<BSTR> ids;
ids.Attach(values.parray);
unsigned int size = ids.GetCount();
for(unsigned int i = 0; i < size; ++i)
{
// use ids[i] here
}
// ...
}
Well, always :) You need it to get a reference to the array content.
But you use a friendly C++ wrapper class. The CComSafeArray<> template already does this for you so you should not help. It uses SafeArrayLock() in the Attach() method, that also returns a pointer to the array content like SafeArrayAccessData() does. And automatically unlocks with its destructor, it runs at the end of your method. Locking otherwise ensures that the array access is thread-safe and cannot be deleted while you are accessing it. There is little danger of that in your existing code, but this squarely fits the better-safe-than-sorry principles of Automation.
Related
I get a data structure like this:
struct My_data
{
MyArray<float> points;
MyArray<float> normals;
MyArray<float> uvCoords;
};
This function can be used to free them:
void ClearAlembicData(My_data* myData)
{
myData->points.clear();
myData->normals.clear();
myData->uvCoords.clear();
}
I want to asynchronously clean the myData so that the program will not wait util all the xxx.clear() are done. Here is my actual code:
My_data myData;
myData.point.push_back(point);
myData.nomals.push_back(nomals);
myData.uvCorrds.push_back(uvCorrds);
ClearAlembicData(&myData);
myData.point.push_back(point);
myData.nomals.push_back(nomals);
myData.uvCorrds.push_back(uvCorrds);
Could you show me how to do it in C++? thanks
Depending on the definition of MyArray, this will either cause undefined behavior or be completely pointless.
If the container is thread-safe, it will block your push_back while the clear is being executed in the other thread (making the 'clearing it asynchronously' completely pointless), if it is not, you are introducing a race condition, which might even end up crashing your program, because you would be concurrently manipulating a shared resource. (Not a good idea).
If you still want to do it, here is a way that might work:
Make 'myData' into a pointer and operate on that.
Upon wanting to clear, store that pointer in another pointer variable and replace the pointer with new My_Data.
Pass the stored pointer to your asynchronous 'free' function.
Continue to work with your new data structure in the original thread.
This way, you are not working on a shared resource and asynchronous freeing becomes feasible.
As for 'how to', if you've got C++11, something like this would work (Pseudo-Code).
My_data *myData = new My_data();
myData->point.push_back(point);
myData->nomals.push_back(nomals);
myData->uvCorrds.push_back(uvCorrds);
std::thread([=](){ ClearAlembicData(myData); delete myData; }).detach();
myData = new My_data()
myData->point.push_back(point);
myData->nomals.push_back(nomals);
myData->uvCorrds.push_back(uvCorrds);
delete myData;
One of the solutions, implement MyArray::swap(MyArray&). Then
void ClearAlembicData(My_data* myData)
{
MyArray<float> old_points;
MyArray<float> old_normal;
MyArray<float> old_coords;
// Fast swap, myData arrays become empty
myData->points.swap(old_points);
myData->normals.clear(old_normals);
myData->uvCoords.clear(old_coords);
// Assumed to be passed to async function
old_points.clear();
old_normals.clear();
old_coords.clear();
}
There is no enough information about MyArray abilities, such as support of move semantics, a real function clear, thus this is just an idea.
If MyArray is a wrapper around std::vector, know that the clear() operation is O(1) as float is trivially destructible and the compiler can eliminate the loop that destroys elements individually.
If it is not, consider implementing MyArray.clear() such that it marks the container as having a non-zero capacity yet zero contents. As stated above, std::vector accomplishes this by simply setting slots_available = capacity.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 8 years ago.
Improve this question
I think my question sounds stupid and welcome downvote on me. If you are implementing a method in C++ which needs to return a pointer, is it safe to do that? If not, why?
Not a simple question. For instance: Best way of returning a pointer.
Ideally, you should try to avoid returning values that come with side-effects or obligations.
// This may be ok, it implies no burden on the user.
Manager* GetManager();
// But what if the user decides to call delete on the value you return?
// This is not unusual in C code, but carries a hidden contract:
// I allocate - you free.
const char* GetFilename(int fd)
{
char* filename = malloc(256);
sprintf(filename, "/tmp/tmpfile.%d", fd);
return filename;
}
C++ is about encapsulation and abstraction. You can codify the contract with your consumer by encapsulating a pointer you want to return. The idea here is that instead of exposing a pointer, you expose an object which is responsible for ownership of the pointer. Infact, recent versions of the language already do this for you with std::unique_ptr, std::shared_ptr and std::weak_ptr.
But a crude, simple RAII example might be:
class StrDupPtr
{
char* m_alloc;
public:
StrDupPtr(const char* src)
: m_alloc(strdup(src))
{}
~StrDupPtr()
{
free(m_alloc);
}
operator const char* () const { return m_alloc; }
// etc.
};
You're still returning a pointer here, but you've encapsulated it with a management contract and removed burden from the end-user to manage your resources.
You can't always avoid it, and when you have to, yes it can be dangerous.
int* AllocateMeSomeMemory()
{
int* memory = malloc(4 * sizeof(int));
// here, have four ints.
return memory;
}
int main() {
int* memory = AllocateMeSomeMemory();
memory[42] = 0xDeath; // yeah, it's not a valid hex number, but that's not really the problem.
}
Another common problem with pointers is that there's no way to tell how many people have them. Here's a contrived example:
void transferItem(userid_t user1, userid_t user2, itemid_t item) {
Account* a1 = GetAccount(user1);
Account* a2 = GetAccount(user2);
if (a1 != a2) {
transferItemInternal(a1, a2, item);
}
delete a2;
delete a1; // Sorry Dave, I can't do that. How about a nice game of CRASH?
}
Normally, a2 and a1 will be different, but when they're not...
Another common failure pattern with pointers is asynchronous callbacks:
// ask the database for user details, call OnLoginResult with userObj when we're done.
void login(int socket, userid_t userId, passwordhash_t pass) {
User* userObj = GetUserObj(userId, socket);
Query* query = Database()->NewQuery("SELECT * FROM user WHERE id = ? AND password = ?", userId, pass);
Database()->Queue(query, OnLoginResult, userObj);
}
void OnDisconnect(int socket, int reason) {
User* userObj = GetUserBySocket(socket);
if (userObj) {
UnregisterUserObj(userObj);
delete userObj;
}
}
void OnLoginResult(void* param) {
User* userObj = static_cast<UserObj*>(param);
// all well and good unless the user disconnected while waiting.
...
}
Yes it is. I assume you mean "Allocate and return" a pointer.
Its common to have initialisation functions which allocate a pointer to an object of some type, and then initialise the object itself. It will then be up to a different part of the program to release the memory.
Well it always depends on what you are doing. A pointer is simply a memory address, so it is similar to simply returning an integer. You should do more research on pointers and how to properly implement them
I sense this question might be closed quite soon, but I'll try to answer anyway.
Yes, it's "safe", as long as you're careful. In fact, it's a very common way to do things, particularly if you're interfacing with C APIs. Having said that, it's best to avoid doing so if you can, because C++ generally provides better alternatives.
Why should you avoid it? Firstly, let's say you have a method that looks like this:
MyStruct* get_data();
Is the return value a pointer to a single instance of MyStruct, or the start of an array? Do you need to free() the returned pointer? Or perhaps you need to use delete? Can the return value be NULL, and what happens if it is? Without looking at the documentation, you have no way of knowing any of these things. And the compiler has no way of knowing either, so it can't help you out in any way.
Better options:
If you want to return an array of values, use a std::array (if the size is fixed at compile-time), or a std::vector (if the size isn't known till run-time).
If you're trying to avoid copying a large struct, then return a reference, or a const reference if possible. That way the caller knows they won't receive a NULL value.
If you really need to return a pointer, than consider using a smart pointer instead -- that will help you sort out ownership issues. For example, std::shared_ptr uses reference counting, and std::unique_ptr ensures that a given pointer only ever has one owner.
I need parse some XML and wrote some helpers. I am not expert in C++, actually I wrote with c more then seven years ago. So, I would to make sure, is the approach, what i use correct or not :)
1) I implemented some simple helpers, to take care about exceptions.
For example:
CComPtr<IXMLDOMElement> create_element(CComPtr<IXMLDOMDocument> xml_doc, string element_name) {
CComPtr<IXMLDOMElement> element;
HRESULT hr = xml_doc->createElement((BSTR)element_name.c_str(), &element);
if (FAILED(hr))
hr_raise("Failed to create XML element '" + element_name + "'", hr);
return element;
}
and use it like this:
void SomeClass::SomeMethod() {
CComPtr<IXMLDOMElement> element = xmlh::create_element(xml_doc, "test");
//..
// save xml to file
}
is it ok? I mean can i return smart pointer as function result? Is this approach free from leaks?
2) Also i use some smartpointer as Class Members.
Like this:
class XMLCommand {
public:
XMLCommand(std::string str_xml);
~XMLCommand(void);
protected:
CComPtr<IXMLDOMDocument> xml_doc;
}
XMLCommand::XMLCommand(string str_xml) {
xml_doc = xmlh::create_xml_doc();
}
// some methods below uses xml_doc
The question is the same, is it correct and free from leaks?
Thanks.
That will work fine. When returning a smart pointer from function, the result is stored before the temporaries are destructed, so as long as you store it in a CComPtr<IXMLDOMElement> when you call create_element you will get the desired results (e.g., CComPtr<IXMLDOMElement> resElem = create_element(...);. Optimized C++ will very likely even not bother with temporaries and such and just use resElem instead of element inside your create_element() method, speeding up the process (google Return Value Optimization for details).
The latter case is pretty much textbook smart-pointer usage. I can't think of a case that will fail. One danger when using smart pointers in general though is to be aware of and/or avoid circular dependencies, which can cause smart pointers to never delete their contained object.
I want to call a method in a COM component from C# using COM interop. This is the methods signature:
long GetPrecursorInfoFromScanNum(long nScanNumber,
LPVARIANT pvarPrecursorInfos,
LPLONG pnArraySize)
and this is sample code (which I checked is really working) to call it in C++:
struct PrecursorInfo
{
double dIsolationMass;
double dMonoIsoMass;
long nChargeState;
long nScanNumber;
};
void CTestOCXDlg::OnOpenParentScansOcx()
{
VARIANT vPrecursorInfos;
VariantInit(&vPrecursorInfos);
long nPrecursorInfos = 0;
m_Rawfile.GetPrecursorInfoFromScanNum(m_nScanNumber,
&vPrecursorInfos,
&nPrecursorInfos);
// Access the safearray buffer
BYTE* pData;
SafeArrayAccessData(vPrecursorInfos.parray, (void**)&pData);
for (int i=0; i < nPrecursorInfos; ++i)
{
// Copy the scan information from the safearray buffer
PrecursorInfo info;
memcpy(&info,
pData + i * sizeof(MS_PrecursorInfo),
sizeof(PrecursorInfo));
}
SafeArrayUnaccessData(vPrecursorInfos.parray);
}
And here's the corresponding C# signature after importing the typelib of the COM component:
void GetPrecursorInfoFromScanNum(int nScanNumber, ref object pvarPrecursorInfos, ref int pnArraySize);
If I'm not mistaken, I need to pass in null for pvarPrecursorInfos to make COM interop marshal it as the expected VT_EMPTY variant. When I'm doing it, I get a SafeArrayTypeMismatchException - not really surprising, looking at how the result is expected to be handled in the sample. So I was trying to use a custom marshaler. Since a cannot alter the component itself, I tried to introduce it this way:
[Guid("06F53853-E43C-4F30-9E5F-D1B3668F0C3C")]
[TypeLibType(4160)]
[ComImport]
public interface IInterfaceNew : IInterfaceOrig
{
[DispId(130)]
int GetPrecursorInfoFromScanNum(int nScanNumber, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshaler))] ref object pvarPrecursorInfos, ref int pnArraySize);
}
The TypeLibType and DispID attribute are the same as in the original version. This works as far as that the MyMarshaller.GetInstance() method is called, but I do not get a callback in MyMarshaller.NativeToManaged. Instead, an access violation is reported. So is this a reliable approach? If yes - how can I make it work? If no: are there any alternatives?
(Just a footnote: in theory I could try to use managed C++ to call the component natively. However, there are lots of other methods in it that work fine with COM interop, so I would very much like to stick with C# if there is any way.)
Since someone asked for it, here's my solution in Managed C++.
array<PrecursorInfo^>^ MSFileReaderExt::GetPrecursorInfo(int scanNumber)
{
VARIANT vPrecursorInfos;
VariantInit(&vPrecursorInfos);
long nPrecursorInfos = -1;
//call the COM component
long rc = pRawFile->GetPrecursorInfoFromScanNum(scanNumber, &vPrecursorInfos, &nPrecursorInfos);
//read the result
//vPrecursorInfos.parray points to a byte sequence
//that can be seen as array of MS_PrecursorInfo instances
//(MS_PrecursorInfo is a struct defined within the COM component)
MS_PrecursorInfo* pPrecursors;
SafeArrayAccessData(vPrecursorInfos.parray, (void**)&pPrecursors);
//now transform into a .NET object
array<PrecursorInfo^>^ infos = gcnew array<PrecursorInfo^>(nPrecursorInfos);
MS_PrecursorInfo currentPrecursor;
for (int i=0; i < nPrecursorInfos; ++i)
{
currentPrecursor = pPrecursors[i];
infos[i] = safe_cast<PrecursorInfo^>(Marshal::PtrToStructure(IntPtr(¤tPrecursor), PrecursorInfo::typeid));
}
SafeArrayUnaccessData(vPrecursorInfos.parray);
return infos;
}
I look at the github code mzLib, which I believe is related to this topic. The code looks good, where it calls
pin_ptr<const wchar_t> wch = PtrToStringChars(path);
I think it may cause some problem, better use
pin_ptr<const wchar_t> pathChar = static_cast<wchar_t*>(System::Runtime::InteropServices::Marshal::StringToHGlobalUni(path).ToPointer());
The code then seems to be worked just fine when compiles. However, it might run in problem when imported as dll. I worked on that by adding a constructor,such as
public ref class ThermoDLLClass
{
public:
ThermoDLLClass();
PrecursorInfo GetPrecursorInfo(int scanNum, String^ path);
};
Then, it seems to get precursorInfo and parameters appropriately.
I find myself in need of help. Now, I'm not all that unfamiliar with C++, but combining it with ATL provides a whole new level of confusion. Anyways, my problem: I (finally) managed to return an array of objects in my COM method to C# caller. But upon 'testing' (running said function a number of times repeatedly) I recognized a small memory leak.
IDL excerpt:
...
interface IDISControl : IDispatch{
...
[id(12)] HRESULT GetNets([out,retval] VARIANT* nets);
};
Header excerpt:
...
STDMETHOD(GetNets)(VARIANT* nets);
...
Code:
STDMETHODIMP CDISControl::GetNets(VARIANT* nets)
{
SNet *netz;
int32_t num;
int result, i;
result = DIS_GetNetNum(securityHandle, &num);
netz = new SNet[num];
result = DIS_GetNet(securityHandle, netz, num); //getting some data
CComSafeArray<IDispatch*> netArray;
CComObject<CDISNet> *net;
CComVariant *var;
netArray.Create(num, 0);
for (i = 0;i<num;i++){
CComObject<CDISNet>::CreateInstance(&net);
if (net == NULL)
return S_FALSE;
net->AddRef();
net->Convert(netz[i]);
netArray[i] = net;
net->Release();
net = NULL;
}
CComVariant val(netArray.Detach());
val.Detach(nets);
delete [] netz;
netArray.Destroy();
return S_OK;
}
I instantiate CDISNet objects and put some data in them (Convert()). I put them in my safearray and release. As I understand it, the responsibility for destroying them is transferred to safearray. Afterwards, I box the array in a VARIANT so I can fill my [out, retval] parameter. Since it's an out parameter, the responsibility for destruction should be transferred to caller (in my case C#, i.e. its GarbageCollector). I dispose of my dynamic array 'netz' and I destroy safearray wrapper.
So what am I missing? What is left allocated? (This project is really making me appreciate all the comforts of .net).
Help. Please.
EDIT: Further debugging revealed to me that the problem is certainely in my CComObject objects. They aren't being deallocated. If I delete net; in each iteration the array also looses data. I'm unsure as how to rectify that...
EDIT2:
Ok, I poked around this code for a bit, and the leak seems to go away when I comment out variant boxing. The problem is that I borrowed this piece of code from Visual Studio sample on safearrays. So, does anyone have any idea what's up with:
CComVariant val(netArray.Detach());
val.Detach(nets);
...and what to do about it?
Most, if not all, of ATL's wrappers follow COM conventions -- they copy/addref incoming data, as their destructor will destroy/release.
So when you pass your detached SAFEARRAY to CComVariant's constructor, it will make a copy of the SAFEARRAY, which means nobody releases the result from CComSafeArray::Detach.
In cases like this, I always found it easier to forego the wrapper for the return value entirely;
nets->vt = VT_ARRAY | VT_DISPATCH;
nets->parray = netArray.Detach();
The alternative would be to pass your CComSafeArray directly to CComVariant's constructor, without calling Detach, but that would cost you an extra copy. I'd prefer the raw access presented above, as it is most straightforward and cheapest.
As to your first edit, what you're doing with AddRef/Release is fine, if somewhat unnecessary. CComObject::CreateInstance returns an object with reference count 0, so the AddRef will bring it to 1, and then assigning it to the CComSafeArray will bump it to 2, and the following Release back down to 1.
Unless the Convert method does anything with the object's reference count (e.g. QueryInterface itself or pass itself to another COM method), you could skip the AddRef/Release pair, and let Convert execute with refcount == 0. Then adding it to the array would increase it, and it would stay alive until released.