Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Construct a string with char* taking ownership

15 views
Skip to first unread message

francis_r

unread,
Oct 30, 2008, 6:41:23 PM10/30/08
to
How can I construct a string using a char pointer without making a
copy, but simply by taking ownership of it?

For example:

size_t len; // will be filled in by createString
char * p = createString(&len); // a function that returns a char
array, caller gets ownership
std::string theString(p, len); // how to create this string without
making a copy?


Best regards,
Francis

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Nevin :-] Liber

unread,
Oct 31, 2008, 2:30:59 AM10/31/08
to
In article
<bb17c808-51f3-4eee...@64g2000hsu.googlegroups.com>,
francis_r <francis....@gmail.com> wrote:

> How can I construct a string using a char pointer without making a
> copy, but simply by taking ownership of it?

You can't. How would std::string even know how to release the space you
give it?

If you need something to take ownership of a C string, you could always
do something like:

struct shared_c_string
{
shared_c_string(char* s = 0) : ptr(s, free) {}
operator const char*() const { return ptr.get(); }

private:
boost::shared_ptr<char> ptr;
};

--
Nevin ":-)" Liber <mailto:ne...@eviloverlord.com> 773 961-1620

Martin Bonner

unread,
Nov 1, 2008, 11:19:26 AM11/1/08
to
On Oct 30, 10:41 pm, francis_r <francis.ramme...@gmail.com> wrote:
> How can I construct a string using a char pointer without making a
> copy, but simply by taking ownership of it?
>
> For example:
>
> size_t len; // will be filled in by createString
> char * p = createString(&len); // a function that returns a char
> array, caller gets ownership
> std::string theString(p, len); // how to create this string without
> making a copy?

What does "gets ownership" mean? Presumably the caller is responsible
for disposing of the memory, the question is "how?". Likely answers
include:
free(p)
CoTaskMemFree(p) (MS Windows specific)
(lots of other platform and library specific calls)

I suppose it is possible it might even be:
delete [] p;
(although in that case, one has to ask why the API didn't return a
std::string or std::vector<char> in the first place.)

There is no way to do (exactly) what you want. Sorry.

francis_r

unread,
Nov 1, 2008, 11:29:04 AM11/1/08
to
On 31 okt, 07:30, "Nevin :-] Liber" <ne...@eviloverlord.com> wrote:
> In article
> <bb17c808-51f3-4eee-8ea0-d743448d7...@64g2000hsu.googlegroups.com>,

> francis_r <francis.ramme...@gmail.com> wrote:
>
> > How can I construct a string using a char pointer without making a
> > copy, but simply by taking ownership of it?
>
> You can't. How would std::string even know how to release the space you
> give it?

Doesn't std::string just need to call 'free'?

Kind regards,

Francis


--

cbarr...@roadrunner.com

unread,
Nov 1, 2008, 11:58:55 AM11/1/08
to
On Oct 31, 2:30 am, "Nevin :-] Liber" <ne...@eviloverlord.com> wrote:
> In article
> <bb17c808-51f3-4eee-8ea0-d743448d7...@64g2000hsu.googlegroups.com>,
> francis_r <francis.ramme...@gmail.com> wrote:
>
> > How can I construct a string using a char pointer without making a
> > copy, but simply by taking ownership of it?
>
> You can't. How would std::string even know how to release the space you
> give it?
>
> If you need something to take ownership of a C string, you could always
> do something like:
>
> struct shared_c_string
> {
> shared_c_string(char* s = 0) : ptr(s, free) {}
> operator const char*() const { return ptr.get(); }
>
> private:
> boost::shared_ptr<char> ptr;
>
> };
>
you prohably should avoid free(0)
a nessted privare access functor like
struct deleter
{
void operator () (void *p)
{ if(p) free(p);
]
for the deleter is safer and since it is private can not be
modified by user like a void (&)(void *) can,


--

annamalai

unread,
Nov 1, 2008, 11:55:33 AM11/1/08
to
On Oct 30, 5:41 pm, francis_r <francis.ramme...@gmail.com> wrote:

(snip)

> size_t len; // will be filled in by createString
> char * p = createString(&len); // a function that returns a char
> array, caller gets ownership
> std::string theString(p, len); // how to create this string without
> making a copy?

The closest you can get to what you want is by making use of the
placement new operator as given in the program below. Also check out
the FAQ on placement new at

http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10

$ cat place.cc
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
char * createString(int len) {
char *dlg = new char[len];
strncpy(dlg, "Missing Rainbow", len);
return dlg;
}
int main() {
size_t len = 30; char *p = createString(len);
string *sp = new (p) string(p, len);
cout << *sp << endl; return 0;
}

$ g++ place.cc
$ ./a.exe
Missing Rainbow
$ g++ --version
g++ (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There
is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.

$

All constructive comments welcome!

Rgds,
anna

--
Civil Disobedience
http://missingrainbow.blogspot.com/2008/07/civil-disobedience.html

Lance Diduck

unread,
Nov 1, 2008, 12:18:12 PM11/1/08
to
On Oct 30, 6:41 pm, francis_r <francis.ramme...@gmail.com> wrote:
> How can I construct a string using a char pointer without making a
> copy, but simply by taking ownership of it?
>
> For example:
>
> size_t len; // will be filled in by createString
> char * p = createString(&len); // a function that returns a char
> array, caller gets ownership
> std::string theString(p, len); // how to create this string without
> making a copy?
>
> Best regards,
> Francis
>
The standard specifically allows so-called "Copy on Write" (COW)
implementations of std::string. It may be that the std::string you are
already using does this in a fashion --i.e. it wont take ownership of
a raw char*., but if you create a string, and never modify it, the
copies are just ref counts of the underlying data. It you attempt to
modify a copy, it does the right thing and creates a real copy.
COW strings fell out of fashion -- however there was never anything
wrong with the concept, just that many people tried to use them for
small string in MT land, and there it is a disaster.
Last time I checked, RoqueWave (now Apache STDCXX) and Gnu libstdc++
both use COW as the default. But that was a while ago.
A string that takes ownership without the ref counts (like the
ownership semantics used in Apache Xerces) is very difficult in fact,
because these do not play well with the STL. STL cannot handle single
ownership objects, regardless of what type of data it holds.
Lance

Nevin :-] Liber

unread,
Nov 1, 2008, 5:37:38 PM11/1/08
to
In article
<8dfc4ae5-b063-4bc8...@v13g2000pro.googlegroups.com>,
cbarr...@roadrunner.com wrote:

> you prohably should avoid free(0)

Why? It is well defined to do nothing.

According to the C89 standard, section 4.10.3.2 (and C99, section
7.20.3.2):

"The free function causes the space pointed to by ptr to be deallocated,
that is, made available for further allocation. If ptr is a null
pointer, no action occurs."

> struct deleter
> {
> void operator () (void *p)
> { if(p) free(p);
> ]
> for the deleter is safer and since it is private can not be
> modified by user like a void (&)(void *) can,

Could you elaborate on what kind of modification you are referring to
here?

--
Nevin ":-)" Liber <mailto:ne...@eviloverlord.com> 773 961-1620

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Nevin :-] Liber

unread,
Nov 1, 2008, 5:43:27 PM11/1/08
to
In article
<b6a0ba67-1626-4b6f...@t18g2000prt.googlegroups.com>,
francis_r <francis....@gmail.com> wrote:

> On 31 okt, 07:30, "Nevin :-] Liber" <ne...@eviloverlord.com> wrote:
> > In article
> > <bb17c808-51f3-4eee-8ea0-d743448d7...@64g2000hsu.googlegroups.com>,
> > francis_r <francis.ramme...@gmail.com> wrote:
> >
> > > How can I construct a string using a char pointer without making a
> > > copy, but simply by taking ownership of it?
> >
> > You can't. How would std::string even know how to release the space you
> > give it?
>
> Doesn't std::string just need to call 'free'?

Not necessarily. It uses std::allocator<char>, which calls ::operator
delete(void*), which may or not call free(), depending on the
implementation, whether or not the default implementation is replaced,
etc.

--
Nevin ":-)" Liber <mailto:ne...@eviloverlord.com> 773 961-1620

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Seungbeom Kim

unread,
Nov 1, 2008, 10:41:55 PM11/1/08
to
annamalai wrote:
> On Oct 30, 5:41 pm, francis_r <francis.ramme...@gmail.com> wrote:
>
>> // how to create this string without making a copy?
>
> The closest you can get to what you want is by making use of the
> placement new operator as given in the program below. Also check out
> the FAQ on placement new at
>
> http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10
>
> $ cat place.cc
> #include <iostream>
> #include <string>
> #include <cstring>
> using namespace std;
> char * createString(int len) {
> char *dlg = new char[len];
> strncpy(dlg, "Missing Rainbow", len);
> return dlg;
> }
> int main() {
> size_t len = 30; char *p = createString(len);
> string *sp = new (p) string(p, len);
> cout << *sp << endl; return 0;
> }

I don't understand what you're doing here. How can you initialize an
std::string object with the same buffer on which the object is to be
placed, and expect it to work correctly? I can easily imagine the code
above will break on an implementation of std::string that uses <size_t,
char*> pair, because the input and output ranges of copying will overlap
but not coincide exactly.

Moreover, it's up to the implementation how std::string manages its
internal buffer, so it is dangerous and wrong to expect string::~string
to free the buffer with delete[] that pairs with the new[] that
createString used.

Back to the OP's question, I don't think the standard provides a
portable way to do what you want. Maybe the standard would have been
better if it had provided the memory management and the other various
string operations in two separate but combinable components. That way,
we could have had various flavours of string classes, including at least
complete-ownership-management, ownership-taking, and ownership-leaving.

--
Seungbeom Kim

cbarr...@roadrunner.com

unread,
Nov 3, 2008, 1:45:14 PM11/3/08
to
On Nov 1, 4:37 pm, "Nevin :-] Liber" <ne...@eviloverlord.com> wrote:
> In article
> <8dfc4ae5-b063-4bc8-9b2f-2b617d97b...@v13g2000pro.googlegroups.com>,

>
> cbarron...@roadrunner.com wrote:
> > you prohably should avoid free(0)
>
> Why? It is well defined to do nothing.
>
> According to the C89 standard, section 4.10.3.2 (and C99, section
> 7.20.3.2):
>
> "The free function causes the space pointed to by ptr to be deallocated,
> that is, made available for further allocation. If ptr is a null
> pointer, no action occurs."
>
> > struct deleter
> > {
> > void operator () (void *p)
> > { if(p) free(p);
> > ]
> > for the deleter is safer and since it is private can not be
> > modified by user like a void (&)(void *) can,
>
> Could you elaborate on what kind of modification you are referring to
> here?
>
shared_ptr has a get deleter function its templated on the type of
deleter so if you pass a void (*f)(void *p) signature of free

typedef void (*Ptf)(void *);

As you wrote the code free is Ptf and any Ptf could be substituted
later since its type is public. [Its a plain old function ptr]

but if you add
private:
struct deleter {void operator () (void *p) {free(p);}

and use a default constructed deleter in the ctor of the shared_ptr
the
type is not publicly available so the deleter can't be changed by s
user.

Does this make sense???


--

Nevin :-] Liber

unread,
Nov 4, 2008, 12:18:15 PM11/4/08
to
In article
<d0c97afd-ddbd-4a62...@w39g2000prb.googlegroups.com>,
cbarr...@roadrunner.com wrote:

> As you wrote the code free is Ptf and any Ptf could be substituted
> later since its type is public. [Its a plain old function ptr]

How does it get substituted? The member variable in question is private:

struct shared_c_string
{
shared_c_string(char* s = 0) : ptr(s, free) {}
operator const char*() const { return ptr.get(); }

private:
boost::shared_ptr<char> ptr;
};

> private:


> struct deleter {void operator () (void *p) {free(p);}
>
> and use a default constructed deleter in the ctor of the shared_ptr
> the
> type is not publicly available so the deleter can't be changed by s
> user.
>
> Does this make sense???

I'm still not getting it. If the variable isn't publicly accessible,
why does it matter what the underlying type of its internal deleter is?

If you could post some example code which demonstrates the problem
(changes the deleter for the private ptr member variable, unless I'm
misunderstanding what the actual problem is) it would aid greatly in
understanding the issue.

--
Nevin ":-)" Liber <mailto:ne...@eviloverlord.com> 773 961-1620

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

0 new messages