From: Joseph M. Newcomer on
See below...
On Tue, 6 Apr 2010 12:38:07 -0700 (PDT), "John H." <oldman_fromthec(a)yahoo.com> wrote:

>Pete Delgado wrote:
>> The above code should crash. You attempt to copy a 14 element (13 characters
>> + terminating null) sequence into a 10 element array. Since you are using a
>> string literal anyway, why not just set the pszTitle member to the literal
>> rather than attempting to copy it into a class member?
>
>For those looking for a little safer example:
>
>class CMyPropertyPage : public CPropertyPage
>{
> public:
> CMyPropertyPage(UINT nIDTemplate, CString csTitle) :
****
That would be
const CString & csTitle
you really have to embrace "const" as a concept. I just rewrote a library, and one of the
things I did was add 'const' to all parameters where appropriate (most of them). We
uncovered several bugs in the library when I did this!

THe use of const is not only good documentation as to what is going on, it often results
in vastly more efficient code. For eample, const CString does not require making a copy
of the CString contents.
joe
*****
****
> CPropertyPage(nIDTemplate),
> m_csTitle(csTitle)
> {
> m_psp.pszTitle = m_csTitle;
> m_psp.dwFlags |= PSP_USETITLE;
> }
> private:
> CString const m_csTitle;
>};
>
>So then you can doing something like the following (assuming you have
>a dialog template resource IDD_PROPPAGE_SMALL and a string table
>resource with an entry IDS_MY_TITLE):
>
>#include "resource.h"
>int main()
>{
> CPropertySheet sheet;
> CMyPropertyPage page(IDD_PROPPAGE_SMALL,
>CString((LPCTSTR)IDS_MY_TITLE));
> sheet.AddPage(&page);
> sheet.SetWizardMode();
> sheet.DoModal();
> return 0;
>}
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: John H. on
Joseph M. Newcomer wrote:
> That would be
> const CString & csTitle
> you really have to embrace "const" as a concept.

Yes I did think about this some. I read various arguments on Usenet
about the pros and cons of passing small strings by reference vs. by
value. Arguments include "reference passing means you can avoid a
copy", counter arguments I have heard are "this is probably premature
optimization" "the optimizing compiler will do this for you anyways"
"you risk introducing aliasing problems". Also from an interface
perspective, it can leave the caller wondering, "does the created
object expect this string to remain valid throughout its life?" This
of course can be addressed through documentation, but I have seen
systems where things are not documented very well. I guess for this
example I landed on the "premature optimization" side (as a title is
likely to be no more than a couple dozen characters) coupled with
"keep the interface simple".

> I just rewrote a library, and one of the
> things I did was add 'const' to all parameters where appropriate (most of them). We
> uncovered several bugs in the library when I did this!
>
> THe use of const is not only good documentation as to what is going on, it often results
> in vastly more efficient code. For eample, const CString does not require making a copy
> of the CString contents.

There was a recent thread on comp.lang.c++ on using const for pass-by-
value parameters. There wasn't much of a consensus on this either, I
guess it comes down to a matter of taste. The pros of having pass-by-
value be const is that it can avoid unintended changes to the value
(bugs) and may make following logic and maintenance easier, and allow
some optimizations. Some cons pointed out were that having const for
the argument is just noise and providing unnecessary detail to the
caller and that it may make following logic and maintenance harder,
and may disallow some optimizations. To help with the "unnecessary
detail" problem one could omit const in the function declaration but
include it in the function definition.

Do you have any thoughts on this stuff?

Also now with VC++ 10 supporting rvalue references, that will be
another option to consider. Although it's probably not too relevant
in the particular case because, as far as I know, CString does not
support "move" semantics. I guess I could have implemented the page's
title with a string class that does support move semantics, in which
case a small optimization might be obtained with a constructor that
uses the rvalue references.

----------------------------

John H wrote:
> #include "resource.h"
> int main()
> {
> CPropertySheet sheet;
> CMyPropertyPage page(IDD_PROPPAGE_SMALL, CString((LPCTSTR)IDS_MY_TITLE));
> sheet.AddPage(&page);
> sheet.SetWizardMode();
> sheet.DoModal();
> return 0;
> }

I forgot the "AfxWinInit(::GetModuleHandle(NULL),
NULL, ::GetCommandLine(), 0);" at the start of the program.
From: Joseph M. Newcomer on
See below..
On Wed, 7 Apr 2010 09:14:54 -0700 (PDT), "John H." <oldman_fromthec(a)yahoo.com> wrote:

>Joseph M. Newcomer wrote:
>> That would be
>> const CString & csTitle
>> you really have to embrace "const" as a concept.
>
>Yes I did think about this some. I read various arguments on Usenet
>about the pros and cons of passing small strings by reference vs. by
>value. Arguments include "reference passing means you can avoid a
>copy", counter arguments I have heard are "this is probably premature
>optimization" "the optimizing compiler will do this for you anyways"
****
If you think of it as optimization, it is probably the wrong reason. If you think of it
as correctly capturing your intent (the string IS a constant!) then it is mandatory.

I think of it as capturing the specification correctly. The optimization is a side
benefit.
*****
>"you risk introducing aliasing problems".
****
Not with CString.
****
>Also from an interface
>perspective, it can leave the caller wondering, "does the created
>object expect this string to remain valid throughout its life?" This
>of course can be addressed through documentation, but I have seen
>systems where things are not documented very well. I guess for this
>example I landed on the "premature optimization" side (as a title is
>likely to be no more than a couple dozen characters) coupled with
>"keep the interface simple".
****
No, an interface that is simple but is not correct is not a valid inteface. The use of
'const' captures the purpose of the interface. Once you have the const, it really doesn't
matter if you pass by reference or value; you have said somehting correct about your
intentions at the interface.
*****
>
>> I just rewrote a library, and one of the
>> things I did was add 'const' to all parameters where appropriate (most of them). We
>> uncovered several bugs in the library when I did this!
>>
>> THe use of const is not only good documentation as to what is going on, it often results
>> in vastly more efficient code. For eample, const CString does not require making a copy
>> of the CString contents.
>
>There was a recent thread on comp.lang.c++ on using const for pass-by-
>value parameters. There wasn't much of a consensus on this either, I
>guess it comes down to a matter of taste. The pros of having pass-by-
>value be const is that it can avoid unintended changes to the value
>(bugs) and may make following logic and maintenance easier, and allow
>some optimizations. Some cons pointed out were that having const for
>the argument is just noise and providing unnecessary detail to the
>caller and that it may make following logic and maintenance harder,
>and may disallow some optimizations. To help with the "unnecessary
>detail" problem one could omit const in the function declaration but
>include it in the function definition.
*****
We found several errors in the library. Since there is *only* pass-by-value in C and C++
("reference" or "pointer" are VALUES that are passed) I don't buy the arguments about
using it for pass-by-value. I believe based on my experience that the use of const
results in cleaner code that is more likely to be correct.

And if you use Best Practice and use the public header file in your own compilation then
the compiler will complain about mismatched parameter types between the declaration and
the definition.
*****
>
>Do you have any thoughts on this stuff?
>
>Also now with VC++ 10 supporting rvalue references, that will be
>another option to consider. Although it's probably not too relevant
>in the particular case because, as far as I know, CString does not
>support "move" semantics. I guess I could have implemented the page's
>title with a string class that does support move semantics, in which
>case a small optimization might be obtained with a constructor that
>uses the rvalue references.
****
rvalue references are really cool, mostly because of what you can do to optimize
pass-by-value. Yes, this is an optimization, but it is an important one for performance
reasons. Most ot the std:: library is now rewritten to handle rvalue references, and the
performance improvements are said to be considerable. It avoids unnecessary copy
operations.

CString actually does not support move semantics, but doesn't need to, because it manages
a reference count. If you try to do something to a string whose refcount is 1, it can use
move semantics because it has the one-and-only copy in hand. As you pass a CString around
by reference, the refcount is update and copy semantics will come into play when required.
It uses copy-on-write semantics (COW), and there are long threads about this in this NG
and elsewhere.

The real error was using a character array; that is always known to be bad practice in
such cases (and was a glaring bug in the example given!). In fact, the use of strcpy,
sprintf, and strcat, among other "dangerous" functions, is now a firable offense in many
companies because it is well-known that thee operations increase the attack surface of
applications. THe other big one is failing to check integer overflow, but that is harder
to enforce.
joe

>
>----------------------------
>
>John H wrote:
>> #include "resource.h"
>> int main()
>> {
>> CPropertySheet sheet;
>> CMyPropertyPage page(IDD_PROPPAGE_SMALL, CString((LPCTSTR)IDS_MY_TITLE));
>> sheet.AddPage(&page);
>> sheet.SetWizardMode();
>> sheet.DoModal();
>> return 0;
>> }
>
>I forgot the "AfxWinInit(::GetModuleHandle(NULL),
>NULL, ::GetCommandLine(), 0);" at the start of the program.
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: John H. on
Joseph M. Newcomer wrote:
> John H. wrote:
> >passing small strings by reference vs. by
> >value. Arguments include
> > "this is probably premature
> >optimization" "the optimizing compiler will do this for you anyways"
> ****
> If you think of it as optimization, it is probably the wrong reason.

Agreed.

> >Also from an interface perspective, I guess for this
> >example I landed on the "keep the interface simple".
> ****
> No, an interface that is simple but is not correct is not a valid inteface. The use of
> 'const' captures the purpose of the interface. Once you have the const, it really doesn't
> matter if you pass by reference or value; you have said somehting correct about your
> intentions at the interface.

I can think of interfaces that have a simple form (non-const
parameters) and a more complex form (const correct parameters), and
both produce the same desired execution. Am I interpreting you right
to by saying that the one that captures "purpose" better is more
valid?

> Since there is *only* pass-by-value in C and C++
> ("reference" or "pointer" are VALUES that are passed)

I was trying to use pass-by-value to mean situations where the value
that is copied is not a reference or pointer. For references or
pointers I will call that pass-by-reference.

> I don't buy the arguments about
> using it for pass-by-value. I believe based on my experience that the use of const
> results in cleaner code that is more likely to be correct.

I am confused. Are you saying that you don't agree with the arguments
that I mentioned for const with pass-by-value, but that there are
other reasons (that you mentioned) to use const with pass-by-value?
Or are you saying that const is only useful with pass-by-reference and
not at all with pass-by-value?

> And if you use Best Practice and use the public header file in your own compilation then
> the compiler will complain about mismatched parameter types between the declaration and
> the definition.

I don't understand. Is "Best Practice" an option in the compiler or
an additional development tool? As far a I know, a conforming
compiler and at least a few versions of the VC compiler will know to
match the following declaration and definition:

// In the foo.h:
void print_x(int num_times);
// In the foo.cpp:
#include "foo.h"
#include <iostream>
void print_x(int const num_times)
{
for(int i=0; i<num_times; ++i)
{
std::cout << 'x';
}
}

This is the idea I was trying to say when I said put const in the
definition but not the declaration. Here, from the caller's point of
view, it seems like an irrelevant detail on whether num_times is a
const parameter or not. The parameter is copied so whatever they
passed cannot be modified anyways. The function should produce the
same result either way. The fact that the implementation doesn't
modify num_times is really something only of interest to the
implementation. A implementation could in fact modify num_times and
still be correct, something like the following (untested):

void print_x(int num_times)
{
for(; num_times > 0; --num_times)
{
std::cout << 'x';
}
}

I think that using const in pass-by-value (as in pass a copy)
parameters has some merits. However looking at most existing code,
this seems like a rare practice.

> CString ... manages
> a reference count. If you try to do something to a string whose refcount is 1, it can use
> move semantics because it has the one-and-only copy in hand. As you pass a CString around
> by reference, the refcount is update and copy semantics will come into play when required.
> It uses copy-on-write semantics (COW)...

Nice to know.

> The real error was using a character array; that is always known to be bad practice in
> such cases (and was a glaring bug in the example given!). In fact, the use of strcpy,
> sprintf...

As this is an MFC forum, I agree with you, and it was a bad example.
Off-topic, I have been doing work lately in an embedded platform where
we don't have CString or std::string or smart pointers, and I got a
little too compfy with these less robust tools.
From: Joseph M. Newcomer on
See below...
On Wed, 7 Apr 2010 15:35:21 -0700 (PDT), "John H." <oldman_fromthec(a)yahoo.com> wrote:

>Joseph M. Newcomer wrote:
>> John H. wrote:
>> >passing small strings by reference vs. by
>> >value. Arguments include
>> > "this is probably premature
>> >optimization" "the optimizing compiler will do this for you anyways"
>> ****
>> If you think of it as optimization, it is probably the wrong reason.
>
>Agreed.
>
>> >Also from an interface perspective, I guess for this
>> >example I landed on the "keep the interface simple".
>> ****
>> No, an interface that is simple but is not correct is not a valid inteface. The use of
>> 'const' captures the purpose of the interface. Once you have the const, it really doesn't
>> matter if you pass by reference or value; you have said somehting correct about your
>> intentions at the interface.
>
>I can think of interfaces that have a simple form (non-const
>parameters) and a more complex form (const correct parameters), and
>both produce the same desired execution. Am I interpreting you right
>to by saying that the one that captures "purpose" better is more
>valid?
****
Yes. I also annotated the library with the __in, __inout, and so on annotations, which
are meta-notations which when using /ANALYZE uncovered at least six fundamental errors in
the implementation. They really were errors.
****
>
>> Since there is *only* pass-by-value in C and C++
>> ("reference" or "pointer" are VALUES that are passed)
>
>I was trying to use pass-by-value to mean situations where the value
>that is copied is not a reference or pointer. For references or
>pointers I will call that pass-by-reference.
****
No, officially, there is no such concept in C or C++. The "pointer" or "reference" (C++)
is a concept that is implemented via pass-pointer-by-value. As an old compiler writer, we
had to really care about the differences like this.And as someone who was trying to do
optimizing compilers and avoiding aliasing problems, 'const' buys a LOT of power for the
optimizer. A const declaration of a pass-by-value parameter actually allows an
optimization knowns as "value propagation" to occur without having to do complex
flow-graph computations. So if I have a const parameter, and the parameter ends up in
ECX, then I know that I can just get it by using the ECX value anywhere. It also says
that I do not expect this parameter to be modified within the function, that is, it is
really a "parameter" and not some funny kind of temporary variable.
****
>
>> I don't buy the arguments about
>> using it for pass-by-value. I believe based on my experience that the use of const
>> results in cleaner code that is more likely to be correct.
>
>I am confused. Are you saying that you don't agree with the arguments
>that I mentioned for const with pass-by-value, but that there are
>other reasons (that you mentioned) to use const with pass-by-value?
>Or are you saying that const is only useful with pass-by-reference and
>not at all with pass-by-value?
****
I have seen several interesting errors caused by someone modifying the parameter in the
code, then someone else later using the parameter as if it was the one passed in from the
caller. So under maintenance, even a "const int" parameter makes more sense, because it
discourages reuse of the parameter name as if it were a local variable.

In fact, I once made a substantial amount of money rewriting a piece of code where the
programmer had an EMBEDDED assignment to the parameter variable in an expression, and the
consequences were fatal. I discovered this in the rewrite because I wrote 'const int' for
the parameter and the compiler complained halfway through the long, complex computation
that someone had assigned to a const variable.

It discourages sloppy programming, catches errors under maintenance, and can result in
smaller, faster code. What's not to like?

****
>
>> And if you use Best Practice and use the public header file in your own compilation then
>> the compiler will complain about mismatched parameter types between the declaration and
>> the definition.
>
>I don't understand. Is "Best Practice" an option in the compiler or
>an additional development tool? As far a I know, a conforming
>compiler and at least a few versions of the VC compiler will know to
>match the following declaration and definition:
****
Best Practice is a technique that programmers use to reduce the possibility of errors.
****
>
>// In the foo.h:
>void print_x(int num_times);
>// In the foo.cpp:
>#include "foo.h"
>#include <iostream>
>void print_x(int const num_times)
****
This normally results in an error from the compiler because the forward reference in the
header file conflicts with the definition. That would be 'const int' not 'int const'.
****
>{
> for(int i=0; i<num_times; ++i)
> {
> std::cout << 'x';
> }
>}
>
>This is the idea I was trying to say when I said put const in the
>definition but not the declaration.
****
I knew that, and that's why I said it wouldn't work.
****
>Here, from the caller's point of
>view, it seems like an irrelevant detail on whether num_times is a
>const parameter or not. The parameter is copied so whatever they
>passed cannot be modified anyways. The function should produce the
>same result either way. The fact that the implementation doesn't
>modify num_times is really something only of interest to the
>implementation. A implementation could in fact modify num_times and
>still be correct, something like the following (untested):
****
Which would be fine if that's the way the language and compilers worked, but that isn't
how they work.
****
>
>void print_x(int num_times)
>{
> for(; num_times > 0; --num_times)
> {
> std::cout << 'x';
> }
>}
>
>I think that using const in pass-by-value (as in pass a copy)
>parameters has some merits. However looking at most existing code,
>this seems like a rare practice.
****
This is the kind of code I believe is properly discouraged by using the const in the
parameter. In a large function, someone is going to assume that num_times at some point
has the same value passed in, and this assumption is violated by the code that modifies
the parameter.
****
>
>> CString ... manages
>> a reference count. If you try to do something to a string whose refcount is 1, it can use
>> move semantics because it has the one-and-only copy in hand. As you pass a CString around
>> by reference, the refcount is update and copy semantics will come into play when required.
>> It uses copy-on-write semantics (COW)...
>
>Nice to know.
>
>> The real error was using a character array; that is always known to be bad practice in
>> such cases (and was a glaring bug in the example given!). In fact, the use of strcpy,
>> sprintf...
>
>As this is an MFC forum, I agree with you, and it was a bad example.
>Off-topic, I have been doing work lately in an embedded platform where
>we don't have CString or std::string or smart pointers, and I got a
>little too compfy with these less robust tools.
****
One of the fascinating phenomena of development history is that there is a large class of
errors I NEVER make any longer, because I use CString, std::vector, CArray, and so on, all
of which have behavior that is well-managed. So I have never had to worry about tracking
down these errors that I used to be so good at finding. I have gotten real comfy with
modern programming tools, and would tend to insist on them in any programming environment.
joe
****
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm