Wednesday, January 28, 2009

comp.lang.c++ - 25 new messages in 15 topics - digest

comp.lang.c++
http://groups.google.com/group/comp.lang.c++?hl=en

comp.lang.c++@googlegroups.com

Today's topics:

* work with strings - 2 messages, 2 authors
http://groups.google.com/group/comp.lang.c++/t/1914bdf095485c7a?hl=en
* G++ takes code, Comeau barfs with "error: qualified name is not allowed" - 3
messages, 3 authors
http://groups.google.com/group/comp.lang.c++/t/84ebee9c76e6331b?hl=en
* Template turing-completeness and code size optimization - 4 messages, 4
authors
http://groups.google.com/group/comp.lang.c++/t/78ed7e50633370aa?hl=en
* Another 'pointer to pointer' question - 1 messages, 1 author
http://groups.google.com/group/comp.lang.c++/t/3222d7f7a556508e?hl=en
* Minimizing Dynamic Memory Allocation - 2 messages, 2 authors
http://groups.google.com/group/comp.lang.c++/t/c71ca35ca2b641b2?hl=en
* C++0x: unique_ptr and std::move - 3 messages, 3 authors
http://groups.google.com/group/comp.lang.c++/t/8fb40687c0b160b9?hl=en
* "lifetime of temporary bound to reference..." - 1 messages, 1 author
http://groups.google.com/group/comp.lang.c++/t/d9d9be987204ca40?hl=en
* const vs #define - 1 messages, 1 author
http://groups.google.com/group/comp.lang.c++/t/3260874be5bc88df?hl=en
* How to understand the C++ specification? - 1 messages, 1 author
http://groups.google.com/group/comp.lang.c++/t/28b14a1308974070?hl=en
* Closing file streams - 1 messages, 1 author
http://groups.google.com/group/comp.lang.c++/t/ba834866d238a9fa?hl=en
* Doubts regarding const and temporaries.. - 1 messages, 1 author
http://groups.google.com/group/comp.lang.c++/t/bbe2b05f98b66310?hl=en
* "error: no matching function for call to " when overloading method of base
class - 2 messages, 2 authors
http://groups.google.com/group/comp.lang.c++/t/556df47a7e0d767a?hl=en
* multiple inheritance, name collision in base classes - 1 messages, 1 author
http://groups.google.com/group/comp.lang.c++/t/8b796c69e0e14079?hl=en
* sorting stl list with predicate - 1 messages, 1 author
http://groups.google.com/group/comp.lang.c++/t/5aa7bc1fd6974fbf?hl=en
* HOT Queues - 1 messages, 1 author
http://groups.google.com/group/comp.lang.c++/t/50fe87f2abf951cf?hl=en

==============================================================================
TOPIC: work with strings
http://groups.google.com/group/comp.lang.c++/t/1914bdf095485c7a?hl=en
==============================================================================

== 1 of 2 ==
Date: Tues, Jan 27 2009 11:44 pm
From: Kai-Uwe Bux


MN wrote:

> On Jan 27, 9:42 am, Triple-DES <DenPlettf...@gmail.com> wrote:
>> On 27 Jan, 07:33, MN <mazouz.nezh...@gmail.com> wrote:
>>
>> > why do I need to add a copy assignment operator to my class ?
>>
>> I advise you to reread Juha's post.
>>
>> In particular, have you tried this?
>>
>> int main()
>> {
>> {
>> string_ s1 = "hello"
>> string_ s2 = s1;
>> }
>>
>> }
>
> I tried your code and have as result:
> s2 = "hello";

That's one possible outcome (in fact a likely one). Nonetheless, you have
undefined behavior.

What you see is a compiler generated copy constructor and assignment
operator at work, since you did not provide them yourself. The compiler
generated assignment operator works member by member and performs
assignments there. The compiler generated copy constructor also recurses on
the members and uses the copy constructor of each member for that member.
For your class, there is only one member:

class string_ {
char* c;
public:
...
};

Now what happens if a string_ str_b is copy constructed from another string_
object, say, str_a? Well, the member str_b.c is constructed from str_a.c.
That is a char* and it will _not cause allocation_. You end up with two
pointers to the _same_ address. Similar remarks apply to the assignment
operator. This is why you observe s2 = "hello". The char* s2.c points to
the same memory location as s1.c, and "hello" happens to reside there.

The catch happens when str_a or str_b or some intermediate temporary with
the same char* member is destroyed. Have a look at your destructor:

string_::~string_ () {
delete []c;
}

If two objects str_a and str_b have the same pointer, i.e., if

str_a.c == str_b.c

then destruction of the first object will ensure that the memory is
deallocated. The remaining object now has an invalid pointer member. Any
operation that dereferences this pointer is undefined behavior. But that's
not all: when the second object is destroyed, the same memory is deleted
another time and you have undefined behavior again because of double
deletion.


Therefore, you should provide a copy constructor that allocates the needed
memory. Your assign() method provided the right blueprint for a good
assignment operator.


Best

Kai-Uwe Bux

== 2 of 2 ==
Date: Wed, Jan 28 2009 2:31 am
From: MN


Kai-Uwe Bux ,
Thank you for explanation, I added a copy constructor and assign copy
to my class 'string_" and tested my program as suggested by Juha.

Here is my code:

#include <iostream>
#include <string.h>
using namespace std;


class string_
{
char* c;
public:
string_ ();
string_ (char* c);
string_ (const string_ & old_string_);
~string_ ();

// Methods
int get_length();
char* display();
char* assign(string_ &s);
char* assign(char* s_c);
bool compare (string_ &s);
char* concatenate(string_ &s);
int find_index(char str);
};


// Null constructor
string_::string_ (){}

// Constructor
string_::string_ (char* s)
{
c = new char[strlen(s)+1];
strcpy(c, s);
}

// Copy constructor
string_::string_(const string_ & old_string_)
{
char *tmp;
tmp = new char[strlen(old_string_.c)+1];
strcpy (tmp, old_string_.c);
c = tmp;
}

string_::~string_ ()
{
delete []c;
}

/
************************************************************************************************
// * Functions
// *
**********************************************************************************************/
inline int string_::get_length ()
{
return strlen (c);
}


char* string_::assign(char* s_c)
{
c = s_c;
return c;

}


//inline char* string_::assign (string_ &s)
char* string_::assign (string_ &s)
{
char *str = new char[strlen(s.c)+ 1]; // can't unuse str because,
What if strlen(s.c) > strlen(c)?
strcpy (str, s.c);
delete []c;
c = str;
return c;
}


char* string_::display()
{
return c;
}

bool string_::compare (string_ &s)
{
if (!strcmp (c, s.c))
return true;
else
return false;
}

char* string_::concatenate(string_ &s)
{
char *conc = new char [strlen(c) + strlen(s.c)+1];
strcpy(conc, c);
strcat(conc, s.c);
delete []c;
c = conc;
return c;
}

int string_::find_index (char str)
{
int i = 0;
while (c[i]!= '\0')
if(c[i]== str)
return i;
else
i++;
return -1;
}

void foo();
void bar(string_ s);
void foo_1();


int main()
{
string_ s1 ("Hello");
string_ s2("test");
char c_char;

// 1- length
cout << "1- Get length: \n";
cout << "s1 = \"" << s1.display() << "\"\n";
cout << "Length of s1 is: "<<s1.get_length () << " characters" <<
"\n";
cout << "s2 = \"" << s2.display() << "\"\n";
cout << "Length of s2 is: "<<s2.get_length () << " characters" << "\n
\n";

// 2- Assign
cout << "2- Assign \"s1\" to \"s2\":\n";
cout << "Before: s2 = \"" << s2.display() << "\"\n";
cout << "After :s2 = " << s2.assign(s1) << "\n\n";


// 3- Compare
cout << "3- Compare two strings:\n";
cout << "s1 = \"" << s1.display() << "\", ";
cout << "s2 = \"" << s2.display() << "\"\n";

if (s1.compare(s2)== true)
cout << "s1 and s2 are equal\n\n";
else
cout << "s1 and s2 are different\n\n";


// 4- Concatenate
cout << "4- Concatenate s1 to s2:\n";
cout << "s1 = \"" << s1.display() << "\", ";
cout << "s2 = \"" << s2.display() << "\"\n";
cout << "Now s2 is \"" << s2.concatenate(s1) << "\"\n\n";


// 5- Find index
cout << "5- Find index in s1:\n";
cout << "Enter a charcter:\n";
cin >> c_char;
int i = s1.find_index (c_char);
if (i == -1)
cout << "Character \"" << c_char << "\" does not exist in \"" <<
s1.display() << "\"\n";
else
cout << "Index of \"" << c_char << "\" in \"" << s1.display() << "\"
is :" << i << "\n";

// 6- Create a copy of s1 using copy constructor
string_ s3(s1);
cout << "\n6- Content of s3 is: " << s3.display() << endl;

cout << "test foo: \n"; foo();

// 7- Test of foo_1
cout << "\nTest of foo_1" << endl;
foo_1();

//8 Test copy assign
string_ s6 ("test s6");
s6.assign("reassign s6"); // Here compiler uses assign copy
cout << s6.display() << endl;

cout << "\nEnd of program\n";
return 0;
}

void foo()
{
string_ s4 = "HI"; // Use of constructor string_(char *s)
string_ s5 = s4; // Use of copy constructor to create s5
cout << "s4 is: " << s4.display() << endl;
cout << "s5 is: " << s5.display() << endl;

} // In this function compiler used copy constructor to create a new
string_ class variable

void bar(string_ s)
{
cout << "Fom bar function: s is: " << s.display() << endl;
}

void foo_1()
{
string_ s = "There"; // Use of constructor string_(char *s)
bar(s); // To pass s to another function, compiler uses
copy constructor to pass s to function bar()

cout << "Length of string_ s is: " << s.get_length() << endl; //
Here simply use of member methods of class string_
}

==============================================================================
TOPIC: G++ takes code, Comeau barfs with "error: qualified name is not allowed
"
http://groups.google.com/group/comp.lang.c++/t/84ebee9c76e6331b?hl=en
==============================================================================

== 1 of 3 ==
Date: Wed, Jan 28 2009 12:40 am
From: Bart van Ingen Schenau


On Jan 28, 1:02 am, Jeff Schwab <j...@schwabcenter.com> wrote:
> red floyd wrote:
> > As far as I can tell, this code should be correct. G++ likes it, but
> > Comeau online hates it.
> > std::vector<line_t> v(
> > std::istream_iterator<line_t>(std::cin),
> > std::istream_iterator<line_t>());
>
> Comeau is mistaking this statement for a function declaration. I
> believe Comeau is at fault, but I would love to be corrected. You can
> work around this issue with:
>
> std::istream_iterator<line_t> in(std::cin), end;
> std::vector<line_t> v(in, end);

No, Comeau is correct here. This is known as C++'s most vexing parse.
The declaration should be parsed as:
v is a function returning std::vector<line_t> and taking as
arguments
- a std::istream_iterator<line_t> named std::cin (with redundant
parentheses), and
- an unnamed pointer to a function returning
std::istream_iterator<line_t> and taking no arguments.

There are two ways to get the intended meaning of an object
declaration:
- Use named iterators as described by Jeff,or
- Add redundant parentheses around one or both of the constructor
arguments:
std::vector<line_t> v(
(std::istream_iterator<line_t>(std::cin)),
(std::istream_iterator<line_t>()));

Bart v Ingen Schenau


== 2 of 3 ==
Date: Wed, Jan 28 2009 5:32 am
From: James Kanze


On Jan 28, 1:02 am, Jeff Schwab <j...@schwabcenter.com> wrote:
> red floyd wrote:
> > As far as I can tell, this code should be correct. G++ likes it, but
> > Comeau online hates it.
> > std::vector<line_t> v(
> > std::istream_iterator<line_t>(std::cin),
> > std::istream_iterator<line_t>());

> Comeau is mistaking this statement for a function declaration.
> I believe Comeau is at fault, but I would love to be
> corrected.

It's an interesting question. It looks like a function
declaration. But as Comeau says, the argument in a function
declaration cannot take a qualified name, so it can't be a
(legal) function declaration. Whether this is enough to
disqualify it as a function declaration or not, however, I don't
know. (If instead of std::cin, he had written just cin, or used
the name of a local variable, there would be no doubt that it
was a function declaration.)

> You can
> work around this issue with:
>
> std::istream_iterator<line_t> in(std::cin), end;
> std::vector<line_t> v(in, end);

The more or less standard solution is to put an extra pair of
parentheses around the arguments, e.g.:

std::vector<line_t> v(
(std::istream_iterator<line_t>(std::cin)),
(std::istream_iterator<line_t>()));

(Putting them around either of the arguments is sufficient, but
there's no harm in being consistent.)

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


== 3 of 3 ==
Date: Wed, Jan 28 2009 7:09 am
From: Jeff Schwab


James Kanze wrote:
> On Jan 28, 1:02 am, Jeff Schwab <j...@schwabcenter.com> wrote:
>> red floyd wrote:
>>> As far as I can tell, this code should be correct. G++ likes it, but
>>> Comeau online hates it.
>>> std::vector<line_t> v(
>>> std::istream_iterator<line_t>(std::cin),
>>> std::istream_iterator<line_t>());
>
>> Comeau is mistaking this statement for a function declaration.
>> I believe Comeau is at fault, but I would love to be
>> corrected.
>
> It's an interesting question. It looks like a function
> declaration. But as Comeau says, the argument in a function
> declaration cannot take a qualified name, so it can't be a
> (legal) function declaration. Whether this is enough to
> disqualify it as a function declaration or not, however, I don't
> know. (If instead of std::cin, he had written just cin, or used
> the name of a local variable, there would be no doubt that it
> was a function declaration.)

Right; I've used the trick of fully-qualifying cin here specifically to
make the "embarrassing" parse illegal. That works with GCC, and I seem
to recall it working with at least Visual Studio 8. I guess the
question is whether the program is even well-formed.

==============================================================================
TOPIC: Template turing-completeness and code size optimization
http://groups.google.com/group/comp.lang.c++/t/78ed7e50633370aa?hl=en
==============================================================================

== 1 of 4 ==
Date: Wed, Jan 28 2009 12:48 am
From: Bart van Ingen Schenau


On Jan 27, 11:45 pm, a.t...@hotmail.it wrote:
> Hello everyone,
>
> I'd like to bother you asking two questions:
> 1) does the turing-completeness of c++ template metalanguage hinders
> templated code optimization? If so, how?
> 2) is it possible to write a c++ compiler that removes ``duplicated
> instantiations'' i.e. template instantiations with different template
> parameters but identical low-level implementation such as,
> presumeably,
> Foo<int*> and Foo<void*>?

Yes, it is possible to write such a compiler (or rather linker). In
fact, it has already been done. The Microsoft linker supports such
optimisations.
Note that enabling these optimisations makes the implementation non-
conforming w.r.t. the C++ standard, as different functions end up
having the same address, which goes contrary to the rules in the C++
standard.

>
> TIA,
>
> Tavs

Bart v Ingen Schenau


== 2 of 4 ==
Date: Wed, Jan 28 2009 1:42 am
From: pjb@informatimago.com (Pascal J. Bourguignon)


Bart van Ingen Schenau <Bart.van.Ingen.Schenau@ict.nl> writes:

> On Jan 27, 11:45 pm, a.t...@hotmail.it wrote:
>> Hello everyone,
>>
>> I'd like to bother you asking two questions:
>> 1) does the turing-completeness of c++ template metalanguage hinders
>> templated code optimization? If so, how?
>> 2) is it possible to write a c++ compiler that removes ``duplicated
>> instantiations'' i.e. template instantiations with different template
>> parameters but identical low-level implementation such as,
>> presumeably,
>> Foo<int*> and Foo<void*>?
>
> Yes, it is possible to write such a compiler (or rather linker). In
> fact, it has already been done. The Microsoft linker supports such
> optimisations.
> Note that enabling these optimisations makes the implementation non-
> conforming w.r.t. the C++ standard, as different functions end up
> having the same address, which goes contrary to the rules in the C++
> standard.

Well it's easy enough to allocate a 'JMP common' instruction for each
function...

--
__Pascal Bourguignon__


== 3 of 4 ==
Date: Wed, Jan 28 2009 2:44 am
From: a.tavs@hotmail.it


joec...@gmail.com ha scritto:

> On Jan 27, 5:45 pm, a.t...@hotmail.it wrote:
> Given a new programming language X, would this hinder or help
> optimizations vs. c++ ? But you don't mention what "X" might be.
>
Ada/Java generics?

> Sure! I don't see why not. In fact, in many cases, compilers remove
> the only instantiation of a template because it is optimized away.
>
Uh, I made a mistake with the 2nd the question, you know, it was late
for me when I wrote the post...
Obviously, if you have the same object code in more than one
instanciation, you can trash all but one instantiation at link time.
What I wanted to ask was: can the compiler optimize space consumption
by guessing that two instantiations Foo<T1> and Foo<T2> /can/ be
compiled into the same object code?

For example the compiler could compile Foo<T1> and Foo<T2>
differently, because of some optimization, writing two different
object files. On the other hand, if I care about space consumption, I
may want to have those instantiations compiled into the same object.


Tavs


== 4 of 4 ==
Date: Wed, Jan 28 2009 5:40 am
From: James Kanze


On Jan 28, 10:42 am, p...@informatimago.com (Pascal J. Bourguignon)
wrote:
> Bart van Ingen Schenau <Bart.van.Ingen.Sche...@ict.nl> writes:
> > On Jan 27, 11:45 pm, a.t...@hotmail.it wrote:

> >> I'd like to bother you asking two questions:
> >> 1) does the turing-completeness of c++ template metalanguage hinders
> >> templated code optimization? If so, how?
> >> 2) is it possible to write a c++ compiler that removes ``duplicated
> >> instantiations'' i.e. template instantiations with different template
> >> parameters but identical low-level implementation such as,
> >> presumeably,
> >> Foo<int*> and Foo<void*>?

> > Yes, it is possible to write such a compiler (or rather linker). In
> > fact, it has already been done. The Microsoft linker supports such
> > optimisations.
> > Note that enabling these optimisations makes the implementation non-
> > conforming w.r.t. the C++ standard, as different functions end up
> > having the same address, which goes contrary to the rules in the C++
> > standard.

> Well it's easy enough to allocate a 'JMP common' instruction for each
> function...

Or just insert a no-op instruction in front of the code, and use
its address for one of the functions. Only when taking the
function's address, of course, and only do this when the code
actually does compare the two addresses. Admittedly, this does
require a bit of intelligence from the linker. But no more than
a lot of other modern optimization techniques.

In practice, I don't know if it is really worth the effort.
Just do it the way Microsoft does, with a compiler switch to
turn it off if you need strict compatibility. Probably 99% of
all programs will never notice, and not need the switch.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

==============================================================================
TOPIC: Another 'pointer to pointer' question
http://groups.google.com/group/comp.lang.c++/t/3222d7f7a556508e?hl=en
==============================================================================

== 1 of 1 ==
Date: Wed, Jan 28 2009 1:29 am
From: Christopher


I want to expand on another post I had asked earlier, but change
something and see if it is still OK.

Old post summary:

Q-
I need to have an array of pointers to something. I do not know how
many I will have until runtime. How do you allocate? It needs to be in
the form: type **, because the API I am using asks for it in that
way.

A-
Use std::vector

#include <vector>

void some_function(int**);

class A
{
A()
{
// append with push_back
for (int i = 1; i < 4; ++i) {
m_integers.push_back( new int(i) );
}

// pass to C API
int** pint = &m_integers[0];
some_function(pint);
}

// add copy, assignment and destructor
// remember to delete the ints

private:
std::vector<int*> m_integers;
};

That worked great. Now I am going to end up having alot of these
buffers, but only need to pass a few to the API. Which ones will be
dynamic. I want to see if I involve a map of pointers, if the code is
still going to be OK. I know a map is not contiguous like a vector,
but I don't know if it matters when I just store pointers in the map?

Lemme see if I can code this example:

#include <vector>

// In thier C API, the buffer is some other thing they do not describe
// I just get a pointer to it. I just made this a vector for the
example
typedef std::vector<int> Buffer;
void some_function(Buffer **);

class A
{
A()
{
// Create the master collection of buffers
Buffer * buffer = new Buffer();
for (int i = 0; i < 3; ++i)
{
buffer->push_back(i);
}
m_master.push_back("Numbers", buffer);

buffer = new Buffer();
for (int i = 0; i < 3; ++i)
{
buffer->push_back(i);
}
m_master.push_back("Indices", buffer);

buffer = new Buffer();
for (int i = 0; i < 3; ++i)
{
buffer->push_back(i);
}
m_master.push_back("Kilometers", buffer);

// Pass only the needed buffers to the C API
m_current.push_back( m_master["Numbers"] );
m_current.push_back( m_master["Indices"] );

Buffer ** pBuffers = &(m_current[0]);
some_function(pBuffers);
}

// add copy, assignment and destructor
// remember to delete allocated memory

private:

typedef std::map<std::string, Buffer *> MasterBufferCollection;
MasterBufferCollection m_master;

typedef std::vector<Buffer *> CurrentBuffers;
CurrentBuffers m_current;
};

==============================================================================
TOPIC: Minimizing Dynamic Memory Allocation
http://groups.google.com/group/comp.lang.c++/t/c71ca35ca2b641b2?hl=en
==============================================================================

== 1 of 2 ==
Date: Wed, Jan 28 2009 1:32 am
From: James Kanze


On Jan 27, 11:29 am, "Alf P. Steinbach" <al...@start.no> wrote:
> * James Kanze:

> [snip]
> >>>>> To avoid leaks, all classes should include a destructor
> >>>>> that releases any memory allocated by the class'
> >>>>> constructor.

> >>>> This is just dumb advice.

> >>> And it contradicts the advice immediately above: "have a
> >>> clear understanding of resource acquisition".

> >>>> Use types that manage their own memory.

> >>> Which is exactly what the "advice" you just called dumb said.

> >> Nope.

> >> The "advice" in the proposed guidelines was to define a
> >> destructor in every class.

> > Where did you see that?

> Top of this quoted section. :-)

The quoted section doesn't say that the user has to define a
destructor. It says that the class must "include a destructor
[user defined or implicit] that releases any memory allocated by
the class' constructor." In other words, the class author
should ensure that any memory allocated by the classes
constructor is released in the destructor---there's nothing
there about having to do so explicitly, just ensuring that it is
done.

Which isn't really very good advice, since most of the time, if
the constructor allocates and destructor releases, you really
shouldn't be using dynamic memory anyway. Of the three reasons
for using dynamic memory:

-- lifetime doesn't correspond to a standard lifetime: if the
constructor allocates, and the destructor releases, it's
exactly the standard lifetime of a class member;

-- size unknown at compile time: that's what std::vector et al.
are for;

-- type unknown at compile time (a polymorphic delegate, for
example); boost_scoped pointer would certainly be worth
considering.

Judging by the software I've seen (in many different domains,
but certainly not all), I'd say that the last reason is the
least frequent.

The rule is also stupid because, of course, classes which do
allocate memory which they own (like std::vector) don't
necessarily do so only in the constructor. It (sort of) implies
that std::vector could skip the destructor, since it allocated
the memory in push_back(), and not in the constructor. (I'm
pretty sure that that's not what was meant, but that's what it
literally says.)

> > I don't see anything about "defining a destructor".

> The statement about "all classes should" is in a coding
> guideline.

And the following words is "include", followed by a description
of what the destructor should do. Obviously, all classes
include a destructor, but not all include a destructor "that
releases any memory allocated by the class constructor". So the
coding guideline is to ensure that the includes destructor does
release any memory allocated by the class constructor. By
whatever means appropriate---making the member a
boost::scoped_ptr<T> instead of a T* would be one means. (Note
that if the class contains a boost::scoped_ptr, it likely needs
a user defined destructor anyway. But that's another issue.)

> [snip]
> > What about a server whose requests can contain arbitrary
> > expressions (e.g. in ASN.1 or XML---both of which support
> > nesting)? The server parses the requests into a tree; since
> > the total size and the types of the individual nodes aren't
> > known at compile time, it must use dynamic allocation. So
> > what happens when you receive a request with literally
> > billions of nodes? Do you terminate the server? Do you
> > artificially limit the number of nodes so that you can't run
> > out of memory? (But the limit would have to be unreasonably
> > small, since you don't want to crash if you receive the
> > requests from several different clients, in different
> > threads.) Or do you catch bad_alloc (and stack overflow,
> > which requires implementation specific code), free up the
> > already allocated nodes, and return an "insufficient
> > resources" error.

> I haven't done that, and as I recall it's one of those things
> that can be debated for years with no clear conclusion. E.g.
> the "jumping rabbit" (whatever that is in French)

(Do you mean "chaud lapin". That's not "jumping rabbit", but "hot
rabbit". With definite lubricious overtones.)

> maintained such a never-ending thread over in clc++m. But I
> think I'd go for the solution of a sub-allocator with simple
> quota management.

That's also a possible solution. I'm certainly not saying that
handling bad_alloc is the only possible solution. Depending on
other factors, it may be the easiest or most appropriate,
however. E.g. if you're using some sort of explicit stack,
rather than a recursive parser, or if you can also arrange to
get a bad_alloc or some other error message on stack overflow.
And you're on a correctly configured OS, which will correctly
report insufficient memory.

> After all, when it works well for disk space management on
> file servers, why not for main memory for this?

Different number of users? Different size of available
resources? Different use patterns? It might work, but there
are enough differences that you can's suppose that it will (or
that it will be the best solution).

> Disclaimer: until I've tried on this problem a large number of
> times, and failed a large number of times with various aspects
> of it, I don't have more than an overall gut-feeling "this
> should work" idea; e.g. I can imagine e.g. Windows finding
> very nasty ways to undermine the scheme... :-)

The biggest problem with trying to catch bad_alloc is that some
systems undermine it. Linux, for example, unless you configure
it specially. Maybe Windows as well; the one time I
experimented with it under Windows (but that was Windows NT with
VC++ 6.0---a long time ago), rather that getting bad_alloc, the
system suspended my process and brought up a pop-up window
suggesting that I terminate other processes. Not a very useful
reaction for a server, where there's no one in front of the
screen, and the connection will time out if I don't respond in a
limited time.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


== 2 of 2 ==
Date: Wed, Jan 28 2009 3:04 am
From: "Alf P. Steinbach"


* James Kanze:
> On Jan 27, 11:29 am, "Alf P. Steinbach" <al...@start.no> wrote:
>> * James Kanze:
>
>> [snip]
>>>>>>> To avoid leaks, all classes should include a destructor
>>>>>>> that releases any memory allocated by the class'
>>>>>>> constructor.
>
>>>>>> This is just dumb advice.
>
>>>>> And it contradicts the advice immediately above: "have a
>>>>> clear understanding of resource acquisition".
>
>>>>>> Use types that manage their own memory.
>
>>>>> Which is exactly what the "advice" you just called dumb said.
>
>>>> Nope.
>
>>>> The "advice" in the proposed guidelines was to define a
>>>> destructor in every class.
>
>>> Where did you see that?
>
>> Top of this quoted section. :-)
>
> The quoted section doesn't say that the user has to define a
> destructor. It says that the class must "include a destructor
> [user defined or implicit] that releases any memory allocated by
> the class' constructor." In other words, the class author
> should ensure that any memory allocated by the classes
> constructor is released in the destructor---there's nothing
> there about having to do so explicitly, just ensuring that it is
> done.

As I see it your interpretation of the wording is meaningless, but we'll
probably not agree on that, so...


[snip]
> The biggest problem with trying to catch bad_alloc is that some
> systems undermine it. Linux, for example, unless you configure
> it specially. Maybe Windows as well; the one time I
> experimented with it under Windows (but that was Windows NT with
> VC++ 6.0---a long time ago), rather that getting bad_alloc, the
> system suspended my process and brought up a pop-up window
> suggesting that I terminate other processes. Not a very useful
> reaction for a server, where there's no one in front of the
> screen, and the connection will time out if I don't respond in a
> limited time.

The reasonable approach for allocating a large chunk of memory for e.g. a
document or for a sub-allocator would IMHO be to use new(std::nothrow), because
the possibility of allocation failure is then part of the normal case outcome.

For Windows one would probably have to call SetErrorMode at app startup.

The documentation doesn't mention whether it affects out-of-memory handling but
the documentation is in general incomplete, and it's not unlikely.


Cheers & hth.,

- Alf

==============================================================================
TOPIC: C++0x: unique_ptr and std::move
http://groups.google.com/group/comp.lang.c++/t/8fb40687c0b160b9?hl=en
==============================================================================

== 1 of 3 ==
Date: Wed, Jan 28 2009 1:35 am
From: MichaƂ 'Khorne' Rzechonek


Hello,

I wanted o understand how rvalue references work, so I took GCC 4.3
with -std=c++0x flag and wrote code below.

What I don't understand is why 2nd assertion fails and move ctor is
not
called. Please enlighten me :)

Side question: does source() function look all right?

#include <iostream>
#include <cassert>

using std::cout;
using std::endl;
using std::move;

template<typename T>
class unique_ptr {
public:
explicit unique_ptr(T *&&a_ptr): m_ptr(a_ptr) {
a_ptr = NULL;
}

unique_ptr(unique_ptr &&p): m_ptr(p.release()) {
cout << "Move" << endl;
}

T *release() {
T *ptr = m_ptr;
m_ptr = NULL;
return ptr;
}

T *get() {
return m_ptr;
}

T *operator->() {
return m_ptr;
}

~unique_ptr() {
if(m_ptr != NULL) {
delete m_ptr;
}
}

private:
unique_ptr(const unique_ptr &);
void operator=(const unique_ptr &);
void operator=(unique_ptr &&p);

T *m_ptr;

};

struct Foo
{
Foo(int a): a(a) {
cout << "Foo::ctor(" << a << ")" << endl;
}

~Foo() {
cout << "Foo::dtor()" << endl;
}

int a;
private:
Foo(const Foo &);
Foo(Foo &&);

};

unique_ptr<Foo> source(int a = 0) {
return move(unique_ptr<Foo>(new Foo(a)));

}

void sink(unique_ptr<Foo> a_foo) {
cout << a_foo->a << endl;

}

int main() {
unique_ptr<Foo> foo( source(1) );
unique_ptr<Foo> bar = move(foo);
assert(foo.get() == NULL); // ok

unique_ptr<Foo> qux( source(2) );
sink( move(qux) );
assert(qux.get() == NULL); // ??
}


== 2 of 3 ==
Date: Wed, Jan 28 2009 3:13 am
From: Niels Dekker - no return address


Michal 'Khorne' Rzechonek wrote:
> I wanted o understand how rvalue references work, so I took GCC 4.3
> with -std=c++0x flag and wrote code below.
>
> What I don't understand is why 2nd assertion fails and move ctor is
> not called. Please enlighten me :)
>
> #include <iostream>
> #include <cassert>
>
> using std::cout;
> using std::endl;
> using std::move;
>
> template<typename T>
> class unique_ptr {
> public:
> explicit unique_ptr(T *&&a_ptr): m_ptr(a_ptr) {
> a_ptr = NULL;
> }
>
> unique_ptr(unique_ptr &&p): m_ptr(p.release()) {
> cout << "Move" << endl;
> }
>
> T *release() {
> T *ptr = m_ptr;
> m_ptr = NULL;
> return ptr;
> }
>
> T *get() {
> return m_ptr;
> }
>
> T *operator->() {
> return m_ptr;
> }
>
> ~unique_ptr() {
> if(m_ptr != NULL) {
> delete m_ptr;
> }
> }
>
> private:
> unique_ptr(const unique_ptr &);
> void operator=(const unique_ptr &);
> void operator=(unique_ptr &&p);
>
> T *m_ptr;
>
> };
>
> struct Foo
> {
> Foo(int a): a(a) {
> cout << "Foo::ctor(" << a << ")" << endl;
> }
>
> ~Foo() {
> cout << "Foo::dtor()" << endl;
> }
>
> int a;
> private:
> Foo(const Foo &);
> Foo(Foo &&);
>
> };
>
> unique_ptr<Foo> source(int a = 0) {
> return move(unique_ptr<Foo>(new Foo(a)));
>
> }
>
> void sink(unique_ptr<Foo> a_foo) {
> cout << a_foo->a << endl;
>
> }
>
> int main() {
> unique_ptr<Foo> foo( source(1) );
> unique_ptr<Foo> bar = move(foo);
> assert(foo.get() == NULL); // ok
>
> unique_ptr<Foo> qux( source(2) );
> sink( move(qux) );
> assert(qux.get() == NULL); // ??
> }

I think the assertion should not fail. Could it be a compiler bug? It
reminds me of GCC Bugzilla Bug 36744 - function modifying argument
received by-value affects caller's variable when passed as rvalue
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36744


> Side question: does source() function look all right?

> unique_ptr<Foo> source(int a = 0) {
> return move(unique_ptr<Foo>(new Foo(a)));

Should work fine without the "move", as unique_ptr<Foo>(...) is an
rvalue already:

unique_ptr<Foo> source(int a = 0) {
return unique_ptr<Foo>(new Foo(a));

(Untested)


HTH, Niels

--
Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
Scientific programmer at LKEB, Leiden University Medical Center

== 3 of 3 ==
Date: Wed, Jan 28 2009 4:16 am
From: SG


On 28 Jan., 10:35, Micha³ 'Khorne' Rzechonek <khor...@gmail.com>
wrote:
> Hello,
>
> I wanted o understand how rvalue references work, so I took GCC 4.3
> with -std=c++0x flag and wrote code below.

[rearranged]

> #include <iostream>
> #include <cassert>

Don't you need <utility> as well for std::move?

> using std::cout;
> using std::endl;
> using std::move;
>
> template<typename T>
> class unique_ptr {
> public:
> explicit unique_ptr(T *&&a_ptr): m_ptr(a_ptr) {
> a_ptr = NULL;
> }

That's unusual. But ok considering current rules. However, the
semantics of "&&" may change, see:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/

I would use

explicit unique_ptr(T * a_ptr): m_ptr(a_ptr) {}

instead.

> unique_ptr(unique_ptr &&p): m_ptr(p.release()) {
> cout << "Move" << endl;
> }
>
> T *release() {
> T *ptr = m_ptr;
> m_ptr = NULL;
> return ptr;
> }
>
> T *get() {
> return m_ptr;
> }
>
> T *operator->() {
> return m_ptr;
> }

The above two functions (get, operator->) should be const. Is there no
overload for operator* ?

> ~unique_ptr() {
> if(m_ptr != NULL) {
> delete m_ptr;
> }
> }

You don't need to check for null pointers here.

>
> private:
> unique_ptr(const unique_ptr &);
> void operator=(const unique_ptr &);
> void operator=(unique_ptr &&p);

You don't need an extra && overload here for operator=.

> T *m_ptr;
>
> };
>
> struct Foo
> {

[snip]

> };
>
> unique_ptr<Foo> source(int a = 0) {
> return move(unique_ptr<Foo>(new Foo(a)));
> }
>
> void sink(unique_ptr<Foo> a_foo) {
> cout << a_foo->a << endl;
>
> }
>
> int main() {
> unique_ptr<Foo> foo( source(1) );
> unique_ptr<Foo> bar = move(foo);
> assert(foo.get() == NULL); // ok
>
> unique_ptr<Foo> qux( source(2) );
> sink( move(qux) );
> assert(qux.get() == NULL); // ??
>
> }

[rearranged]

> What I don't understand is why 2nd assertion fails and move ctor is
> not called. Please enlighten me :)

It fails? That's odd. I can't test it myself right now, unfortunately.
I guess it's either a compiler bug or we overlooked something.

> Side question: does source() function look all right?

Yes. You don't need the extra move(), though. You only need move() if
you want to return a function's parameter or some other lvalue
reference as rvalue. Local variables (not including call-by-value
parameters) are automatically treated as rvalues in a return
statement.

Cheers!
SG

==============================================================================
TOPIC: "lifetime of temporary bound to reference..."
http://groups.google.com/group/comp.lang.c++/t/d9d9be987204ca40?hl=en
==============================================================================

== 1 of 1 ==
Date: Wed, Jan 28 2009 1:40 am
From: James Kanze


On Jan 27, 2:49 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> James Kanze wrote:
> > On Jan 26, 7:25 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> >> Igor R. wrote:
> >>> Does the rule in the subj applies to the following:

> > First, very importantly, the rule in the subject doesn't
> > exist. Whether a temporary is bound to a reference has no
> > effect on its lifetime. The only time the lifetime of a
> > temporary is extended is if a reference is initialized with
> > a rvalue. (The difference, of course, is whether a
> > temporary is bound to a reference is a transitive
> > relationship; whether a temporary was initialized with an
> > rvalue isn't.)

> I believe you're attempting to split hairs. Please see the
> second sentence of 12.2/5. "The temporary to which the
> reference is bound ... persists for the lifetime of the
> reference". If that's not "lifetime of temporary bound to
> reference", what exactly is it?

That's an interesting quote, because of course, it's neither
implementable, nor implemented.

My point wasn't meant to split hairs. It was to point out a
very important distinction: the fact that the extension of
lifetime is not transitive. The lifetime is only extended to
match that of the reference which was initialized with the
expression generating the temporary. The fact that some
reference is bound to a temporary doesn't guarantee that that
temporary will not be destroyed while the reference is still
usable.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

==============================================================================
TOPIC: const vs #define
http://groups.google.com/group/comp.lang.c++/t/3260874be5bc88df?hl=en
==============================================================================

== 1 of 1 ==
Date: Wed, Jan 28 2009 2:17 am
From: James Kanze


On Jan 27, 5:49 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> Jose Luis wrote:
> > Given the code below:
> > <<<snip begin>>>

> > m3vmsa3.rraaupma /tmp > more p1.c p2.c defs.h

> > #include "defs.h"

> > int main()
> > {}
>
> > ...skipping...

> > #include "defs.h"
> > ...skipping...
> > #ifndef DEFS_H
> > #define DEFS_H

> > const char* STR1="Hello World";
> > const int i1=0;

> >

No comments: