std::string and APIs 
Author Message
 std::string and APIs

There is something that has been puzzling me for a long time, and now
I am in the middle of doing something where it is causing me a lot of
hassle. So I thought I'd try and sort it out.

It is about using std::string's as arguments to API calls
(particularly Win32).

If the API call requires a const char*, like SetWindowText, everything
is easy:

HWND hWnd;
hWnd = ...;
std::string strContent = "BlahBlah";
SetWindowText(hWnd, strContent.c_str());
...

But if it needs a non-const char*, like GetWindowText, what I have
been doing is

HWND hWnd;
hWnd = ...;
std::string strContent;
char szBuffer[1000];
GetWindowText(hWnd, szBuffer, 1000);
strContent = szBuffer;
...

IMO, this is (a) very ugly and (b) potentially dangerous. OK, it's not
so dangerous in the case of something simple like GetWindowText,
because 1000 bytes is 'bound' (!) to be enough, but in other cases you
might not know how long the result is likely to be.
Also, the buffer remains allocated until it goes out of scope, which
might be a long time. Yes, I know you can say:

HWND hWnd;
hWnd = ...;
std::string strContent;
{
        char szBuffer[1000];
        GetWindowText(hWnd, szBuffer, 1000);
        strContent = szBuffer;

Quote:
}

...

but that is even uglier!

So, is there any more elegant way, preferably one which does not
require me to allocate the temporary buffer.

TIA

Pablo Canary



Tue, 18 May 2004 23:01:02 GMT  
 std::string and APIs
std::string MyGetWindowText(HWND hWnd)
{
  int n = GetWindowTextLength(hWnd);
  char* s = _alloca(n);
  GetWindowText(hWnd, s, n);
  return std::string(s);

Quote:
}

HWND hWnd = ...;
std::string strContent = MyGetWindowText(hWnd);


Quote:
> There is something that has been puzzling me for a long time, and now
> I am in the middle of doing something where it is causing me a lot of
> hassle. So I thought I'd try and sort it out.

> It is about using std::string's as arguments to API calls
> (particularly Win32).

> If the API call requires a const char*, like SetWindowText, everything
> is easy:

> HWND hWnd;
> hWnd = ...;
> std::string strContent = "BlahBlah";
> SetWindowText(hWnd, strContent.c_str());
> ...

> But if it needs a non-const char*, like GetWindowText, what I have
> been doing is

> HWND hWnd;
> hWnd = ...;
> std::string strContent;
> char szBuffer[1000];
> GetWindowText(hWnd, szBuffer, 1000);
> strContent = szBuffer;
> ...

> IMO, this is (a) very ugly and (b) potentially dangerous. OK, it's not
> so dangerous in the case of something simple like GetWindowText,
> because 1000 bytes is 'bound' (!) to be enough, but in other cases you
> might not know how long the result is likely to be.
> Also, the buffer remains allocated until it goes out of scope, which
> might be a long time. Yes, I know you can say:

> HWND hWnd;
> hWnd = ...;
> std::string strContent;
> {
> char szBuffer[1000];
> GetWindowText(hWnd, szBuffer, 1000);
> strContent = szBuffer;
> }
> ...

> but that is even uglier!

> So, is there any more elegant way, preferably one which does not
> require me to allocate the temporary buffer.

> TIA

> Pablo Canary



Wed, 19 May 2004 00:40:54 GMT  
 std::string and APIs
Hi!

Am I being a bit thick or does that example leak?

Neil Groves


Quote:
> std::string MyGetWindowText(HWND hWnd)
> {
>   int n = GetWindowTextLength(hWnd);
>   char* s = _alloca(n);
>   GetWindowText(hWnd, s, n);
>   return std::string(s);
> }

> HWND hWnd = ...;
> std::string strContent = MyGetWindowText(hWnd);



> > There is something that has been puzzling me for a long time, and now
> > I am in the middle of doing something where it is causing me a lot of
> > hassle. So I thought I'd try and sort it out.

> > It is about using std::string's as arguments to API calls
> > (particularly Win32).

> > If the API call requires a const char*, like SetWindowText, everything
> > is easy:

> > HWND hWnd;
> > hWnd = ...;
> > std::string strContent = "BlahBlah";
> > SetWindowText(hWnd, strContent.c_str());
> > ...

> > But if it needs a non-const char*, like GetWindowText, what I have
> > been doing is

> > HWND hWnd;
> > hWnd = ...;
> > std::string strContent;
> > char szBuffer[1000];
> > GetWindowText(hWnd, szBuffer, 1000);
> > strContent = szBuffer;
> > ...

> > IMO, this is (a) very ugly and (b) potentially dangerous. OK, it's not
> > so dangerous in the case of something simple like GetWindowText,
> > because 1000 bytes is 'bound' (!) to be enough, but in other cases you
> > might not know how long the result is likely to be.
> > Also, the buffer remains allocated until it goes out of scope, which
> > might be a long time. Yes, I know you can say:

> > HWND hWnd;
> > hWnd = ...;
> > std::string strContent;
> > {
> > char szBuffer[1000];
> > GetWindowText(hWnd, szBuffer, 1000);
> > strContent = szBuffer;
> > }
> > ...

> > but that is even uglier!

> > So, is there any more elegant way, preferably one which does not
> > require me to allocate the temporary buffer.

> > TIA

> > Pablo Canary



Thu, 20 May 2004 08:03:03 GMT  
 std::string and APIs
I'm a C++ newbie. Please be gentle if this is wrong.

HWND hWnd;
hWnd = ...;
std::string strContent;

{
int n = GetWindowTextLength(hWnd);
GetWindowText(hWnd, strContent.begin(), n + 1);
MessageBox(NULL, strContent.c_str(), "The Window Title of hWnd is...", 0);

Quote:
}

I'm using stlport snapshot 111501
Drake

BTW, I see stlport 4.5.1 was just released 12/02/01... off to compile!

Quote:

> There is something that has been puzzling me for a long time, and now
> I am in the middle of doing something where it is causing me a lot of
> hassle. So I thought I'd try and sort it out.

> It is about using std::string's as arguments to API calls
> (particularly Win32).

> If the API call requires a const char*, like SetWindowText, everything
> is easy:

> HWND hWnd;
> hWnd = ...;
> std::string strContent = "BlahBlah";
> SetWindowText(hWnd, strContent.c_str());
> ...

> But if it needs a non-const char*, like GetWindowText, what I have
> been doing is

> HWND hWnd;
> hWnd = ...;
> std::string strContent;
> char szBuffer[1000];
> GetWindowText(hWnd, szBuffer, 1000);
> strContent = szBuffer;
> ...

> IMO, this is (a) very ugly and (b) potentially dangerous. OK, it's not
> so dangerous in the case of something simple like GetWindowText,
> because 1000 bytes is 'bound' (!) to be enough, but in other cases you
> might not know how long the result is likely to be.
> Also, the buffer remains allocated until it goes out of scope, which
> might be a long time. Yes, I know you can say:

> HWND hWnd;
> hWnd = ...;
> std::string strContent;
> {
>    char szBuffer[1000];
>    GetWindowText(hWnd, szBuffer, 1000);
>    strContent = szBuffer;
> }
> ...

> but that is even uglier!

> So, is there any more elegant way, preferably one which does not
> require me to allocate the temporary buffer.

> TIA

> Pablo Canary



Fri, 21 May 2004 05:10:31 GMT  
 std::string and APIs

Quote:

> I'm a C++ newbie. Please be gentle if this is wrong.

> HWND hWnd;
> hWnd = ...;
> std::string strContent;

> {
> int n = GetWindowTextLength(hWnd);
> GetWindowText(hWnd, strContent.begin(), n + 1);
> MessageBox(NULL, strContent.c_str(), "The Window Title of hWnd is...", 0);
> }

It may work, but it's not a very good idea to do it this way.  First,
although std::string's iterators may be implemented as char *'s, they
may not as well, and if they aren't, your call to GetWindowText breaks.
Second, if you don't do something to pre-allocate in strContent, you'll
overwrite memory after it, and be very lucky not to corrupt the heap
and/or cause a GPF.  Third, doing it that way relies on std::string
being contiguous in memory, which is neither guaranteed nor intended
to be.

It's preferable to use std::vector if you want an automatically
managed buffer.  While std::vector is not guaranteed to be contiguous
in the standard, an upcoming TC will add that guarantee and all
known implementations work that way.

So change to:

{
    int n = GetWindowTextLength(hWnd);
    std::vector<char> Buffer(n + 1);
    GetWindowText(hWnd, &Buffer[0], n+1);
    MessageBox(NULL, &Buffer[0], "Window Title", 0);
    strContent = &Buffer[0];
    // Or put the MessageBox here and use c_str member

Quote:
}



Fri, 21 May 2004 23:39:36 GMT  
 std::string and APIs

Quote:



> > std::string MyGetWindowText(HWND hWnd)
> > {
> >   int n = GetWindowTextLength(hWnd);
> >   char* s = _alloca(n);
> >   GetWindowText(hWnd, s, n);
> >   return std::string(s);
> > }

> > HWND hWnd = ...;
> > std::string strContent = MyGetWindowText(hWnd);

> Hi!

> Am I being a bit thick or does that example leak?

I don't think it leaks, he's using _alloca to allocate memory off the
stack, so it should get cleaned up automatically upon leaving the
function.


Fri, 21 May 2004 23:40:54 GMT  
 std::string and APIs
Thank you Craig for explaining the error of my ways. I re-read the
std::string docs and I understand each of the points you make.

This thread has taught me quite a bit. To me, _alloca seemes to be
cleanest. Vector is too expensive (in the context of the original
post).

Thanks,

Drake

Quote:


> > I'm a C++ newbie. Please be gentle if this is wrong.

> > HWND hWnd;
> > hWnd = ...;
> > std::string strContent;

> > {
> > int n = GetWindowTextLength(hWnd);
> > GetWindowText(hWnd, strContent.begin(), n + 1);
> > MessageBox(NULL, strContent.c_str(), "The Window Title of hWnd is...", 0);
> > }

> It may work, but it's not a very good idea to do it this way.  First,
> although std::string's iterators may be implemented as char *'s, they
> may not as well, and if they aren't, your call to GetWindowText breaks.
> Second, if you don't do something to pre-allocate in strContent, you'll
> overwrite memory after it, and be very lucky not to corrupt the heap
> and/or cause a GPF.  Third, doing it that way relies on std::string
> being contiguous in memory, which is neither guaranteed nor intended
> to be.

> It's preferable to use std::vector if you want an automatically
> managed buffer.  While std::vector is not guaranteed to be contiguous
> in the standard, an upcoming TC will add that guarantee and all
> known implementations work that way.

> So change to:

> {
>     int n = GetWindowTextLength(hWnd);
>     std::vector<char> Buffer(n + 1);
>     GetWindowText(hWnd, &Buffer[0], n+1);
>     MessageBox(NULL, &Buffer[0], "Window Title", 0);
>     strContent = &Buffer[0];
>     // Or put the MessageBox here and use c_str member
> }



Sat, 22 May 2004 03:37:19 GMT  
 std::string and APIs
Remember that 1) _alloca is non-standard and 2) usually the stack space is
limited (I believe about 4M by default on Wintel machines). _alloca only
releases memory when the function returns. Using _alloca to allocate large
buffers, or calling it many times in a loop, can easily cause stack
overflow.
--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat, and
wrong." H.L. Mencken


Quote:
> Thank you Craig for explaining the error of my ways. I re-read the
> std::string docs and I understand each of the points you make.

> This thread has taught me quite a bit. To me, _alloca seemes to be
> cleanest. Vector is too expensive (in the context of the original
> post).

> Thanks,

> Drake




Quote:

> > > I'm a C++ newbie. Please be gentle if this is wrong.

> > > HWND hWnd;
> > > hWnd = ...;
> > > std::string strContent;

> > > {
> > > int n = GetWindowTextLength(hWnd);
> > > GetWindowText(hWnd, strContent.begin(), n + 1);
> > > MessageBox(NULL, strContent.c_str(), "The Window Title of hWnd is...",
0);
> > > }

> > It may work, but it's not a very good idea to do it this way.  First,
> > although std::string's iterators may be implemented as char *'s, they
> > may not as well, and if they aren't, your call to GetWindowText breaks.
> > Second, if you don't do something to pre-allocate in strContent, you'll
> > overwrite memory after it, and be very lucky not to corrupt the heap
> > and/or cause a GPF.  Third, doing it that way relies on std::string
> > being contiguous in memory, which is neither guaranteed nor intended
> > to be.

> > It's preferable to use std::vector if you want an automatically
> > managed buffer.  While std::vector is not guaranteed to be contiguous
> > in the standard, an upcoming TC will add that guarantee and all
> > known implementations work that way.

> > So change to:

> > {
> >     int n = GetWindowTextLength(hWnd);
> >     std::vector<char> Buffer(n + 1);
> >     GetWindowText(hWnd, &Buffer[0], n+1);
> >     MessageBox(NULL, &Buffer[0], "Window Title", 0);
> >     strContent = &Buffer[0];
> >     // Or put the MessageBox here and use c_str member
> > }



Sat, 22 May 2004 04:34:39 GMT  
 std::string and APIs
Is this really a good idea in terms of performance?  It seems like the
constructor gets called then the destructor the copy constructor?  Lets
suppose I used this function this way:
{
   std::string mystring = MyGetWindowText(hWnd);
Quote:
}

Now the std::string constructor gets called by MyGetWindow functions return
statement.  It is using memory off the stack which is freed and its
destructor gets called. Then mystrings copy constructor must be called as
well.  By the way, internally std::string uses an allocator function to get
memory for the string it contains i.e. malloc.  It does not just point to
whatever you pass it.  It allocates memory and copies the string.
Fortunately the destructor get called to free it.

The way I usually handle this is as follows:

std::string& MyGetWindowText(HWND hWnd, std::string& mystring)
{
  int n = GetWindowTextLength(hWnd);
  char* s = static_cast<char*>_alloca(n);
  GetWindowText(hWnd, s, n);
  return mystring = s;

Quote:
}

Now
{
   std::string mystring;
   GetWindowText(hWnd,mystring);

Quote:
}

Only one constructor is called and no destructors.


Quote:
> std::string MyGetWindowText(HWND hWnd)
> {
>   int n = GetWindowTextLength(hWnd);
>   char* s = _alloca(n);
>   GetWindowText(hWnd, s, n);
>   return std::string(s);
> }

> HWND hWnd = ...;
> std::string strContent = MyGetWindowText(hWnd);



> > There is something that has been puzzling me for a long time, and now
> > I am in the middle of doing something where it is causing me a lot of
> > hassle. So I thought I'd try and sort it out.

> > It is about using std::string's as arguments to API calls
> > (particularly Win32).

> > If the API call requires a const char*, like SetWindowText, everything
> > is easy:

> > HWND hWnd;
> > hWnd = ...;
> > std::string strContent = "BlahBlah";
> > SetWindowText(hWnd, strContent.c_str());
> > ...

> > But if it needs a non-const char*, like GetWindowText, what I have
> > been doing is

> > HWND hWnd;
> > hWnd = ...;
> > std::string strContent;
> > char szBuffer[1000];
> > GetWindowText(hWnd, szBuffer, 1000);
> > strContent = szBuffer;
> > ...

> > IMO, this is (a) very ugly and (b) potentially dangerous. OK, it's not
> > so dangerous in the case of something simple like GetWindowText,
> > because 1000 bytes is 'bound' (!) to be enough, but in other cases you
> > might not know how long the result is likely to be.
> > Also, the buffer remains allocated until it goes out of scope, which
> > might be a long time. Yes, I know you can say:

> > HWND hWnd;
> > hWnd = ...;
> > std::string strContent;
> > {
> > char szBuffer[1000];
> > GetWindowText(hWnd, szBuffer, 1000);
> > strContent = szBuffer;
> > }
> > ...

> > but that is even uglier!

> > So, is there any more elegant way, preferably one which does not
> > require me to allocate the temporary buffer.

> > TIA

> > Pablo Canary



Sat, 22 May 2004 15:57:49 GMT  
 std::string and APIs
You have optimized performance at the expense of a messy
interface.  Whether that is a desirable tradeoff depends on the
usage pattern.



Quote:
> Is this really a good idea in terms of performance?  It seems like the
> constructor gets called then the destructor the copy constructor?  Lets
> suppose I used this function this way:
> {
>    std::string mystring = MyGetWindowText(hWnd);
> }
> Now the std::string constructor gets called by MyGetWindow functions
return
> statement.  It is using memory off the stack which is freed and its
> destructor gets called. Then mystrings copy constructor must be called as
> well.  By the way, internally std::string uses an allocator function to
get
> memory for the string it contains i.e. malloc.  It does not just point to
> whatever you pass it.  It allocates memory and copies the string.
> Fortunately the destructor get called to free it.

> The way I usually handle this is as follows:

> std::string& MyGetWindowText(HWND hWnd, std::string& mystring)
> {
>   int n = GetWindowTextLength(hWnd);
>   char* s = static_cast<char*>_alloca(n);
>   GetWindowText(hWnd, s, n);
>   return mystring = s;
> }

> Now
> {
>    std::string mystring;
>    GetWindowText(hWnd,mystring);
> }

> Only one constructor is called and no destructors.




- Show quoted text -

Quote:
> > std::string MyGetWindowText(HWND hWnd)
> > {
> >   int n = GetWindowTextLength(hWnd);
> >   char* s = _alloca(n);
> >   GetWindowText(hWnd, s, n);
> >   return std::string(s);
> > }

> > HWND hWnd = ...;
> > std::string strContent = MyGetWindowText(hWnd);



Sat, 22 May 2004 20:24:33 GMT  
 
 [ 10 post ] 

 Relevant Pages 

1. How can I use std::string in api that expects char* ?

2. convert non std::string to std::string

3. convert between std::string and std::wstring

4. Warnings for std::vector<std::string>

5. typedef std::vector<std::string> Vector_String

6. std::hash_map with std::string as a key

7. basic std::stringstream and std::string questions

8. int to std::string to System::String

9. static std::string exposed through System::String *

10. String to std:string

11. System::String to std::string

12. System.String to std::string conversion

 

 
Powered by phpBB® Forum Software