The function below works, but it's seems to me it has very bad smell.
My project communicate with device over HTTP, it has some url with digest authentication, some pages without.
Some url compressed with deflate, some none.
So my function has 3 different way to get istream.
And i need to read istream in one place in the bottom of function.
But as said good people from another my question C++ variable visable scopes and strems, pointers in this case is bad.
And in this code in some cases creates dynamic object.
Poco::InflatingInputStream* inflater = new Poco::InflatingInputStream(*respStreamPtr);
And this is path to memory leaks?
If create inflater without new statement, then *respStreamPtr has no data out of if block scope.
So, please give me advice how to refactor this code in right way.
std::ostream& requestStream = session->sendRequest(request);
istream* respStreamPtr;
respStreamPtr = &session->receiveResponse(response);
if (response.getStatus() == HTTPResponse::HTTP_UNAUTHORIZED)
{
credentials->authenticate(request, response);
session->sendRequest(request);
respStreamPtr = &session->receiveResponse(response);
}
if (response.has("Content-Encoding") && response.get("Content-Encoding") == "deflate") {
Poco::InflatingInputStream* inflater = new Poco::InflatingInputStream(*respStreamPtr);
respStreamPtr = &std::istream(inflater->rdbuf());
}
std::ostringstream stringStream;
stringStream << respStreamPtr->rdbuf();
responseBody = stringStream.str();
Yes, that will be a memory leak, as every time you use new it will create a new object, which you never delete
However, you use the inflater variable outside of the scope it's declared in, so currently have no way of nicely deleting it without modifying other code. For a simple fix, you could just declare Poco::InflatingInputStream* inflater = nullptr; at the top of your code, then delete it at the end.
I'd strongly recommend reading up on how to manage memory correctly in c++, and even taking a look at smart pointers (but not without learning the fundamentals first)
Poco actually has functionality which does a lot of what you're trying to do, so your example could be easily condensed (disclaimer: untested):
session->sendRequest(request);
auto& responseStream = session->receiveResponse(response);
if (response.getStatus() == HTTPResponse::HTTP_UNAUTHORIZED)
{
credentials->authenticate(request, response);
session->sendRequest(request);
responseStream = session->receiveResponse(response);
}
if (response.has("Content-Encoding") && response.get("Content-Encoding") == "deflate")
{
Poco::InflatingInputStream inflater(responseStream);
StreamCopier::copyStream(inflater, responseStream);
}
responseBody << responseStream;
Related
I'm currently developing application using gSoap library and has some misunderstanding of proper usage library. I has generated proxy object (-j flag) which wrapped my own classes, as you can see below. Application must work 24/7 and connect simultaneously to many cameras (~50 cameras), so after every request i need to clear all temporary data. Is it normal usage to call soap_destroy() and soap_end() after every request? Because it seem's overkill to do it after each request. May be exists another option of proper usage?
DeviceBindingProxy::destroy()
{
soap_destroy(this->soap);
soap_end(this->soap);
}
class OnvifDeviceService : public Domain::IDeviceService
{
public:
OnvifDeviceService()
: m_deviceProxy(new DeviceBindingProxy)
{
soap_register_plugin(m_deviceProxy->soap, soap_wsse);
}
int OnvifDeviceService::getDeviceInformation(const Access::Domain::Endpoint &endpoint, Domain::DeviceInformation *information)
{
_tds__GetDeviceInformation tds__GetDeviceInformation;
_tds__GetDeviceInformationResponse tds__GetDeviceInformationResponse;
setupUserPasswordToProxy(endpoint);
m_deviceProxy->soap_endpoint = endpoint.endpoint().c_str();
int result = m_deviceProxy->GetDeviceInformation(&tds__GetDeviceInformation, tds__GetDeviceInformationResponse);
m_deviceProxy->soap_endpoint = NULL;
if (result != SOAP_OK) {
Common::Infrastructure::printSoapError("Fail to get device information.", m_deviceProxy->soap);
m_deviceProxy->destroy();
return -1;
}
*information = Domain::DeviceInformation(tds__GetDeviceInformationResponse.Manufacturer,
tds__GetDeviceInformationResponse.Model,
tds__GetDeviceInformationResponse.FirmwareVersion);
m_deviceProxy->destroy();
return 0;
}
}
To ensure proper allocation and deallocation of managed data:
soap_destroy(soap);
soap_end(soap);
You want to do this often to avoid memory to fill up with old data. These calls remove all deserialized data and data you allocated with the soap_new_X() and soap_malloc() functions.
All managed allocations are deleted with soap_destroy() followed by soap_end(). After that, you can start allocating again and delete again, etc.
To allocate managed data:
SomeClass *obj = soap_new_SomeClass(soap);
You can use soap_malloc for raw managed allocation, or to allocate an array of pointers, or a C string:
const char *s = soap_malloc(soap, 100);
Remember that malloc is not safe in C++. Better is to allocate std::string with:
std::string *s = soap_new_std__string(soap);
Arrays can be allocated with the second parameter, e.g. an array of 10 strings:
std::string *s = soap_new_std__string(soap, 10);
If you want to preserve data that otherwise gets deleted with these calls, use:
soap_unlink(soap, obj);
Now obj can be removed later with delete obj. But be aware that all pointer members in obj that point to managed data have become invalid after soap_destroy() and soap_end(). So you may have to invoke soap_unlink() on these members or risk dangling pointers.
A new cool feature of gSOAP is to generate deep copy and delete function for any data structures automatically, which saves a HUGE amount of coding time:
SomeClass *otherobj = soap_dup_SomeClass(NULL, obj);
This duplicates obj to unmanaged heap space. This is a deep copy that checks for cycles in the object graph and removes such cycles to avoid deletion issues. You can also duplicate the whole (cyclic) managed object to another context by using soap instead of NULL for the first argument of soap_dup_SomeClass.
To deep delete:
soap_del_SomeClass(obj);
This deletes obj but also the data pointed to by its members, and so on.
To use the soap_dup_X and soap_del_X functions use soapcpp2 with options -Ec and -Ed, respectively.
In principle, static and stack-allocated data can be serialized just as well. But consider using the managed heap instead.
See https://www.genivia.com/doc/databinding/html/index.html#memory2 for more details and examples.
Hope this helps.
The way memory has to be handled is described in Section 9.3 of the GSoap documentation.
The documentation for ICU states that
Starting with ICU 4.4, it is possible to set several data packages,
one per call to this function. udata_open() will look for data in the
multiple data packages in the order in which they were set.
However, I would like udata_open() to look for data in the reverse order, so that as soon as I add a new udata_setCommonData, I can overwrite any previous data with my new data. Obviously if an object which uses data has been instantiated, it will use the old set, but any new data should use the new data. I'm guessing that the answer is somewhere in udata.cpp near doLoadFromCommonData, hopefully it is not too complicated to make this change. In that function, I see
if (!isICUData) {
return NULL;
} else if (pCommonData != NULL) {
++commonDataIndex; /* try the next data package */
} else if ((!checkedExtendedICUData) && extendICUData(subErrorCode)) {
checkedExtendedICUData = TRUE;
/* try this data package slot again: it changed from NULL to non-NULL */
} else {
return NULL;
I suspect I want to start at the top and use --commonDataIndex instead.
Update. I discovered that I can also swap out the contents as long as the pointer is the same and re-run udata_setCommonData. Perhaps this is a good solution that avoids having to modify the ICU code. Just need to allocate the maximum possible size I might encounter - which .. perhaps might be trickier.
Alternatively, a way to unsetCommonData might be good too.
Or, making storing a pointer to a pointer to the data instead of the pointer to the data in
for (i = 0; i < LENGTHOF(gCommonICUDataArray); ++i) {
if (gCommonICUDataArray[i] == NULL) {
gCommonICUDataArray[i] = newCommonData;
ucln_common_registerCleanup(UCLN_COMMON_UDATA, udata_cleanup);
didUpdate = TRUE;
break;
} else if (gCommonICUDataArray[i]->pHeader == pData->pHeader) {
/* The same data pointer is already in the array. */
break;
}
The only safe (or sane) way to do this is to call u_cleanup() and start over. Otherwise this is not good usage of ICU at all, and highly un-recommended. Sorry.
If you want to dynamically update data, make a feature request, or better yet contribute the code for it.
I want something like this:
if (customLocation.isEmpty())
{
KUrl url;
}
else
{
KUrl url(customLocation);
}
/* use url */
Any reason you can't do
KUrl url;
if (!customLocation.isEmpty())
{
url = KUrl(customLocation);
}
/* use url */
or
KUrl url = customLocation.isEmpty() ? KUrl() : KUrl(customLocation);
The usual C++ constructs intentionally create a very tight coupling between allocation and initialization. Thus, ordinarily you would need to use dynamic allocation to be able to dynamically specify the constructor to use. And dynamic allocation is probably some orders of magnitude more inefficient than the slight overhead that you're trying to avoid…
However, with C++11 you can use aligned storage and placement new.
The catch is that the KUrl class will most likely use dynamic allocation internally, and then all that the optimization accomplishes is to waste programmer's time: both your time initially, and the time of anyone later maintaining the code.
Any reason why this won't work?
KUrl url;
if (!customLocation.isEmpty())
url = customLocation;
KUrl url;
if (!cusomLocation.isEmpty())
{
url = KUrl( customLocation );
}
Here you have no copy of KUrl being done
boost::optional<KUrl> ourl;
if(customLocation.isEmpty()) {
ourl = boost::in_place();
} else {
ourl = boost::in_place(customLocation);
}
KUrl &url = *ourl;
Fun aside, I would recommend Jacks solutions (if it works with your type) :)
I am writing an application using the crypto++ library. For those not familiar with it, the ECB_Mode template classes inherit from CipherModeBase. The program compiles and runs, but the output I am getting is incorrect. When I call the encryption method from the cipher_object, it doesn't work the same way as if I use an ECB_Mode object directly. I have verified that the options object instance variables are getting assigned correctly. I would like to create the instances within an if_then_else structure or switch_case so I can keep the code nice and DRY. What am I doing wrong?
Here is what I am trying but doesn't work:
CipherModeBase *cipher_object;
cipher_object == NULL;
if(options->cipher == BS_AES)
{
ECB_Mode<AES >::Encryption ecbEncryption(options->key, options->keylen);
cipher_object = &ecbEncryption;
}
else if(options->cipher == BS_TWOFISH)
{
ECB_Mode<Twofish >::Encryption ecbEncryption(options->key, options->keylen);
cipher_object = &ecbEncryption;
}
cipher_object->processData(args);
Here is what does work:
ECB_Mode<AES >::Encryption ecbEncryption(options->key, options->keylen);
ecbEncryption.processData(args);
PS. I know not to use ECB mode. I just don't want to mess with IVs until I can get everything working. I am also relatively inexperienced with C++.
Your ecbEncryption objects are declared on the stack within the if and else scopes. (Scopes are the things enclosed by curly brackets).
An object will be destroyed when the scope it was declared in exits. So, the object you're calling processData on has been deleted before you call that method. Clearly that won't work.
One option is you could declare the objects on the heap instead of the stack. That way the lifetime could be controlled to work the way you want.
Try to use a std::unique_ptr for the cipher_object instead of a raw pointer. Then, in the if and else clauses assign to it like:
cipher_object.reset( new ECB_Mode<AES>::Encryption(options->key, options->keylen) );
Then the object will remain on the heap until the end of the cipher_object's scope, at which point the unique_ptr will delete it for you. And, the cipher_object's scope will last until after you call any methods on it.
Here:
cipher_object == NULL;
if(options->cipher == BS_AES)
{
// v
ECB_Mode<AES >::Encryption ecbEncryption(options->key, options->keylen);
cipher_object = &ecbEncryption;
}
ecbEncryption is local to that scope. You are storing the address of a local, and using it after it goes out of scope. That's undefined behaviour. You should allocate it on the heap using the new keyword:
if(options->cipher == BS_AES)
{
cipher_object = new ECB_Mode<AES >::Encryption(options->key, options->keylen);
}
You should do the same for the other if statement.
Also note that this:
cipher_object == NULL;
Should be changed to this:
cipher_object = NULL;
The problem should be solved using the above code, though.
I used to be a C++ expert a decade ago, but for the past 10 years I've been programming Java. I just started a C++ project that uses a small third-party XML parser. The XML parser accepts an STL istream. My XML data is coming from a Windows COM IStream. I thought I'd do the Right Thing and create an adapter to take the IStream data and present it to the XML parser through an istream.
I followed the excellent tutorial at http://www.mr-edd.co.uk/blog/beginners_guide_streambuf and created a COMStreambuf that takes data from the underlying COM IStream, and used it as a buffer for a custom COMIstream. Everything looks good, but I get a read error from the parser.
Turns out the parser reads the whole file into memory by using seekg() on the istream to find out its size and then goes back to the beginning with seekg() to read it in one go. Unsurprisingly, the aforementioned tutorial decided to "save [instructions on implementing seeking] for another post" which was apparently never written.
Can someone tell me what I need to do to implement seekg() with my custom istream/streambuf? I would venture out doing it myself (my first inclination would be to override stuff in istream), but with my inexperience this deep in the STL and with my Java mentality I fear I would do something incomplete and have a brittle solution. (Without reading tutorials, for example, I never would have guessed that one makes a custom istream by writing a new streambuf, for example, or that I would need to call imbue() with a default locale, etc.)
Thanks for any help. I've been very impressed with this site---both with the knowledge of the participants and their friendly, honest nature in conceding who has the best answer. :)
I assume that by "seekg" you mean seekoff and seekpos.
The straightforward way to implement members seekoff and seekpos of your COMStreambuf is to wrap the Seek method of the IStream interface. For example, something like this should work:
// COMStreambuf.cpp
COMStreambuf::pos_type COMStreambuf::seekoff(COMStreambuf::off_type off_, std::ios_base::seekdir way_, std::ios_base::openmode which_)
{
union {
LARGE_INTEGER liMove;
ULARGE_INTEGER uliMove;
};
liMove.QuadPart = off_;
DWORD dwOrigin = STREAM_SEEK_SET;
if (way_ == std::ios_base::cur) {
dwOrigin = STREAM_SEEK_CUR;
} else if (way_ == std::ios_base::end) {
dwOrigin = STREAM_SEEK_END;
} else {
assert(way_ == std::ios_base::beg);
dwOrigin = STREAM_SEEK_SET;
uliMove.QuadPart = off_;
}
ULARGE_INTEGER uliNewPosition;
if (which_ & std::ios_base::in) {
if (which_ & std::ios_base::out)
return pos_type(off_type(-1));
HRESULT hres = streamIn->Seek(liMove, dwOrigin, &uliNewPosition);
if (hres != S_OK)
return pos_type(off_type(-1));
setg(eback(), egptr(), egptr());
} else if (which_ & std::ios_base::out) {
HRESULT hres = streamOut->Seek(liMove, dwOrigin, &uliNewPosition);
if (hres != S_OK)
return pos_type(off_type(-1));
setp(pbase(), epptr(), epptr());
} else {
return pos_type(off_type(-1));
}
return pos_type(uliNewPosition.QuadPart);
}
COMStreambuf::pos_type COMStreambuf::seekpos(COMStreambuf::pos_type sp_, std::ios_base::openmode which_)
{
return seekoff(off_type(sp_), std::ios_base::beg, which_);
}
In this listing, after setting the position of streamIn I call:
setg(eback(), egptr(), egptr());
After a seek, sputbackc or sungetc will operate on old data. You may want to consider whether this makes sense for your application and do something different.