POV-Ray : Newsgroups : povray.off-topic : Undirected ramblings on C++ Server Time
26 Dec 2024 02:17:57 EST (-0500)
  Undirected ramblings on C++ (Message 1 to 10 of 13)  
Goto Latest 10 Messages Next 3 Messages >>>
From: Orchid Win7 v1
Subject: Undirected ramblings on C++
Date: 27 Feb 2014 14:23:11
Message: <530f909f$1@news.povray.org>
One of the most unexpected outcomes of my current employment is the 
amount of time I spend writing C++ code.

I remember I did spend a while dabbling with C++ years ago. (I think I 
even got Warp to install Haskell round about the same time...) But I 
never managed to write much beyond Hello World with it. But now, I find 
myself writing highly non-trivial code in C++. And that's kind of 
alarming, given I know nothing about C++...

I'm always immensely surprised when I compile the code, and it actually 
*works*. It seems so unlikely that my naively cobbled-together nonsense 
could ever function correctly. But somehow, it does. (Sometimes!)

I lose count of the number of times I've spent an hour or so writing 
some C++ code in Visual Studio, I send my work to source control, and 
GCC chokes on it and refuses to compile it. I honestly can't figure out 
whether this is a defect of GCC or VS.

For example, yesterday I wrote the following code:

   auto iter = inputs.begin();

VS happily accepted this declaration, and the code performed the way I 
had intended it to. But GCC emitted some gabled message to the effect 
that "iter" hasn't been declared or some such... Replacing the "auto" 
keyword with an explicit type signature fixed the problem. But I didn't 
think this was an especially new language feature...

In a similar vein, today I tried giving a variable the same name as a 
class. VS didn't care; it compiled and ran my code just fine. GCC gave 
me an utterly baffling error message which took me some considerable 
while to figure out. Renaming the variable made it happy again.

I can't figure out whether VS is being too permissive or GCC is being 
too restrictive, but the two frequently differ on what is and isn't 
permissible code. (And then there's the preprocessor macros - but we 
*know* those are evil...)

Not that VS is perfect, of course. Yesterday it gave me the dreaded 
C2512 error: "no appropriate default constructor available". I searched 
the Internet, and EVERY SINGLE QUESTION about this involved a class 
where somebody had *clearly* defined a custom constructor, thereby 
disabling the automatic creation of a default constructor. My class, by 
contrast, had NO METHODS AT ALL, let alone a constructor. WTF?

As best as I can tell, this is somehow due to it being impossible to 
auto-initialise reference fields? Not that any error message *told* me 
this or anything like that...

Speaking of which... I think I may be fundamentally misunderstanding 
what references actually *do*. I had thought they were like pointers, 
just that you can't make them null. But some sources claim they're like 
pointers who's value can never change. So what, pray tell, does the 
following do?

   std::vectpr<int> foo;
   std::vector<int> bar;
   std::vector<int> & baz = foo;
   baz = bar;

I had imagined that the final line changes baz from pointing to foo and 
to instead point to bar. But... if a reference can never change... then 
what the hell am I changing?? O_O

It's times like these that make me want to step away from the keyboard 
and go for a walk outside for a while. This stuff is just too 
complicated to be left to mere mortals. It should only be touched by 
people with a PhD in the official language spec.



If there's one thing that's more astonishing than writing complex C++ 
code and having it *work*, it's calling that code from a real 
programming language and having *that* work!

I still can't quite believe that I wrote a complicated regular 
expression parsing and matching engine in C++, and built a Windows DLL 
out of it, and called it from C#. Literally, our application has a C# 
class in it. It looks for all the world like a perfectly ordinary C# 
class. But every time you invoke a method, it's actually running C++ 
code. Dynamically loaded from a DLL at runtime. And it freaking works! 8-O

Of course, if it doesn't work, good luck ever figuring out what the 
problem is! :-P

Hell, today I even wrote a Haskell wrapper around the DLL. So I'm 
sitting there writing all this ultra-high-level code that tranposes 
linked lists and stuff, and somewhere deep in the computer's innards 
it's actually running clunky old C++ code. Weird, but true.

(Actually, I recently added a new feature to the regular expression 
engine. It was so hard, I wrote it in Haskell first, so I could figure 
out the algorithm. And then I spent an entire day trying to get C++ to 
do it. It's almost shocking how tiny the Haskell implementation is... 
This is no trivial algorithm!)


Post a reply to this message

From: Le Forgeron
Subject: Re: Undirected ramblings on C++
Date: 27 Feb 2014 15:08:59
Message: <530f9b5b@news.povray.org>
Le 27/02/2014 20:23, Orchid Win7 v1 nous fit lire :
> Speaking of which... I think I may be fundamentally misunderstanding
> what references actually *do*. I had thought they were like pointers,
> just that you can't make them null. But some sources claim they're like
> pointers who's value can never change. So what, pray tell, does the
> following do?
> 
>   std::vectpr<int> foo;
>   std::vector<int> bar;
>   std::vector<int> & baz = foo;
>   baz = bar;
> 
> I had imagined that the final line changes baz from pointing to foo and
> to instead point to bar. But... if a reference can never change... then
> what the hell am I changing?? O_O

Reference are pointer which never changes (in the lifetime of the
reference), and which cannot be invalid (nullptr). But the referee can
be changed. (the object stay the same, but the content can change).

A non assigned reference cannot exist. The creation must assign it. And
once assigned, you cannot assign it a new value.
But that does not apply to the referenced content/object. it can be
change (or rather, updated).

foo is a sequence of int.
bar is a sequence of int.
baz is a reference to foo, so it's a sequence of int too.
foo, via baz, got its values replaced by the one of bar.

Gcc default to C++98 or C++03.. if you want more on the line of auto,
you need -std=c++0x or -std=c++11 (and you should use g++, as gcc is the
C front-end of the compiler, and auto has other meaning in C than in C++)

if you want real fun, look at lambda expression. The pointer to function
of C are just a dull feature... especially with some capture and some copy.

From C++ standpoint, you shouldn't need macro (excepted for protecting
include file with #ifndef FOO/define FOO/.../#endif... you have template
and other items like enum)


Post a reply to this message

From: nemesis
Subject: Re: Undirected ramblings on C++
Date: 27 Feb 2014 17:05:01
Message: <web.530fb5abd7ab15f4ebb90cbd0@news.povray.org>
Orchid Win7 v1 <voi### [at] devnull> wrote:
> One of the most unexpected outcomes of my current employment is the
> amount of time I spend writing C++ code.
>
> I remember I did spend a while dabbling with C++ years ago. (I think I
> even got Warp to install Haskell round about the same time...) But I
> never managed to write much beyond Hello World with it. But now, I find
> myself writing highly non-trivial code in C++. And that's kind of
> alarming, given I know nothing about C++...
>
> I'm always immensely surprised when I compile the code, and it actually
> *works*. It seems so unlikely that my naively cobbled-together nonsense
> could ever function correctly. But somehow, it does. (Sometimes!)

LOL

but yeah, most C++ already look like gibberish, so why not just expect anything
to just work (TM)?


Post a reply to this message

From: Warp
Subject: Re: Undirected ramblings on C++
Date: 27 Feb 2014 18:27:37
Message: <530fc9e9@news.povray.org>
Orchid Win7 v1 <voi### [at] devnull> wrote:
> For example, yesterday I wrote the following code:

>    auto iter = inputs.begin();

> VS happily accepted this declaration, and the code performed the way I 
> had intended it to. But GCC emitted some gabled message to the effect 
> that "iter" hasn't been declared or some such... Replacing the "auto" 
> keyword with an explicit type signature fixed the problem. But I didn't 
> think this was an especially new language feature...

Currently gcc will only accept C++11 code if you give the -std=c++11
command-line parameter to it (or -std=c++0x if you are using a slightly
older version of gcc). That's probably the problem you are having.
(I don't know when they will change gcc to accept C++11 by default.)

> In a similar vein, today I tried giving a variable the same name as a 
> class. VS didn't care; it compiled and ran my code just fine. GCC gave 
> me an utterly baffling error message which took me some considerable 
> while to figure out. Renaming the variable made it happy again.

I suppose I'd have to see an actual example to give an informed opinion.

> Not that VS is perfect, of course. Yesterday it gave me the dreaded 
> C2512 error: "no appropriate default constructor available".

Again, I'd have to see an actual example...

> As best as I can tell, this is somehow due to it being impossible to 
> auto-initialise reference fields? Not that any error message *told* me 
> this or anything like that...

In general, you can't make a reference point to a temporary.

> Speaking of which... I think I may be fundamentally misunderstanding 
> what references actually *do*. I had thought they were like pointers, 
> just that you can't make them null. But some sources claim they're like 
> pointers who's value can never change. So what, pray tell, does the 
> following do?

>    std::vectpr<int> foo;
>    std::vector<int> bar;
>    std::vector<int> & baz = foo;
>    baz = bar;

> I had imagined that the final line changes baz from pointing to foo and 
> to instead point to bar. But... if a reference can never change... then 
> what the hell am I changing?? O_O

"A reference can never change" means that you can't make it point to some
other object after initialization. It doesn't mean you can't change
whatever it's referencing.

In the above example "baz = bar;" is doing the exact same thing as
"foo = bar;" (because 'baz' is an "alias" to 'foo' via the fact that
it's a reference to it.) In other words, you are assigning the 'bar'
object to the 'foo' object by value (via the 'baz' reference.)

> It's times like these that make me want to step away from the keyboard 
> and go for a walk outside for a while. This stuff is just too 
> complicated to be left to mere mortals. It should only be touched by 
> people with a PhD in the official language spec.

I don't think it's that hard. A reference is basically an "alias" to
whatever it's referring to. Whatever you are doing to the reference
you are doing to the original.

(The "immutability" of the refence, if we can call it that, simply means
that you can't later make it an "alias" to some other object. It will
always be an "alias" to the object it was initialized with.)

-- 
                                                          - Warp


Post a reply to this message

From: Lars R 
Subject: Re: Undirected ramblings on C++
Date: 28 Feb 2014 03:23:20
Message: <53104778$1@news.povray.org>
On 02/27/2014 08:23 PM, Orchid Win7 v1 wrote:
> One of the most unexpected outcomes of my current employment is the
> amount of time I spend writing C++ code.
> 
> I remember I did spend a while dabbling with C++ years ago. (I think I
> even got Warp to install Haskell round about the same time...) But I
> never managed to write much beyond Hello World with it. But now, I find
> myself writing highly non-trivial code in C++. And that's kind of
> alarming, given I know nothing about C++...

I know that moment. I've also written a lot of C++ code until I realized
that I don't really _know_ the language.

I _really_ learned it when I had to give a C++ course to my colleagues.
I had (and still have) the expectation to myself to only teach what's
true. So I had to study a lot of C++'s hidden details, read the ISO
standard etc. to be sure that I tell always the truth in my course and
my pupils can rely on my words.

That reminds me on a movie quote (from "Contact"): "I had no idea!"


> For example, yesterday I wrote the following code:
> 
>   auto iter = inputs.begin();
> 
> VS happily accepted this declaration, and the code performed the way I
> had intended it to. But GCC emitted some gabled message to the effect
> that "iter" hasn't been declared or some such... Replacing the "auto"
> keyword with an explicit type signature fixed the problem. But I didn't
> think this was an especially new language feature...

You wrote C++11 code. gcc (at least up to 4.7) does C++11 code only when
requested explicitly (-std=c++11, or -std=c++0x in older compiler versions).

Don't know whether gcc 4.8 or 4.9 switch its default mode to C++11.


> Speaking of which... I think I may be fundamentally misunderstanding
> what references actually *do*. I had thought they were like pointers,

Wrong, totally wrong. Imagine C++ references just as "alias names" (to
existing objects).

Whether they might be implemented using pointers internally is not
relevant, because they just don't behave like pointers (or references in
Java) at all.

They are alias names. Nothing more.

>   std::vectpr<int> foo;
>   std::vector<int> bar;
>   std::vector<int> & baz = foo;
>   baz = bar;
>
> I had imagined that the final line changes baz from pointing to foo and
> to instead point to bar. But... if a reference can never change... then
> what the hell am I changing?? O_O

Hence "baz" is just an alias for "foo", you change "foo" if you change
"baz". That's easy, isn't it? :-)

Lars R.


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: Undirected ramblings on C++
Date: 28 Feb 2014 03:28:31
Message: <531048af$1@news.povray.org>
>> In a similar vein, today I tried giving a variable the same name as a
>> class. VS didn't care; it compiled and ran my code just fine. GCC gave
>> me an utterly baffling error message which took me some considerable
>> while to figure out. Renaming the variable made it happy again.
>
> I suppose I'd have to see an actual example to give an informed opinion.

   struct Side
   {
     Pattern & Pattern;
     Pattern::iterator Iterator;
   }

The error message was something like "cannot change meaning of 'class 
Pattern' to 'Pattern'" or something equally cryptic. Renaming the first 
field fixed the problem.

>> Not that VS is perfect, of course. Yesterday it gave me the dreaded
>> C2512 error: "no appropriate default constructor available".
>
> Again, I'd have to see an actual example...

   struct Side
   {
     Pattern & Pattern;
     Pattern::iterator & Iterator;
   }

   struct State
   {
     Side & LeftSide;
     Side & RightSide;
     std::stringstream Buffer;
     bool Success;
   }

Every single line that declares a State variable gives me C2512. As you 
can see, I clearly *have not* defined any constructors, so that isn't 
the reason for a default constructor not existing.

>> Speaking of which... I think I may be fundamentally misunderstanding
>> what references actually *do*. I had thought they were like pointers,
>> just that you can't make them null. But some sources claim they're like
>> pointers who's value can never change. So what, pray tell, does the
>> following do?
>
>>     std::vectpr<int>  foo;
>>     std::vector<int>  bar;
>>     std::vector<int>  &  baz = foo;
>>     baz = bar;
>
>> I had imagined that the final line changes baz from pointing to foo and
>> to instead point to bar. But... if a reference can never change... then
>> what the hell am I changing?? O_O
>
> "A reference can never change" means that you can't make it point to some
> other object after initialization. It doesn't mean you can't change
> whatever it's referencing.
>
> In the above example "baz = bar;" is doing the exact same thing as
> "foo = bar;" (because 'baz' is an "alias" to 'foo' via the fact that
> it's a reference to it.) In other words, you are assigning the 'bar'
> object to the 'foo' object by value (via the 'baz' reference.)

So what you're saying is, a reference is a pointer where you can't ever 
change the *address* it points to, but you can change what's *at* that 
address?

Does that also mean that assigning one vector to another actually 
*copies* the entire vector? As in, a deep copy??

>> It's times like these that make me want to step away from the keyboard
>> and go for a walk outside for a while. This stuff is just too
>> complicated to be left to mere mortals. It should only be touched by
>> people with a PhD in the official language spec.
>
> I don't think it's that hard. A reference is basically an "alias" to
> whatever it's referring to. Whatever you are doing to the reference
> you are doing to the original.

I didn't mean references specifically. I just meant the entire language. 
Nobody would try to claim that C++ is small or simple or free of 
surprises. For example,

    struct Side
    {
      Pattern & ThePattern;
      Side(Pattern p) : ThePattern(p) {}
    }

Guess what? This segfaults when I run it. *You* probably see the problem 
immediately, but it took me 24 hours to figure out that there's a single 
missing character there...

Today it's references. Last time it was

   catch (std::exception e)
   {
     std::cout << e.what();
   }

which *always* says std::exception, even if that wasn't the exception 
thrown. The time before that, it was a memory leak due to an (empty) 
destructor not being virtual. There's so many buts and gotchas. And 
they're not the sort of thing where your program gives you the wrong 
answer; they're the sort of thing where you have a native crash and 
you're left utterly bewildered as to how the *hell* to discover what the 
problem was...


Post a reply to this message

From: Le Forgeron
Subject: Re: Undirected ramblings on C++
Date: 28 Feb 2014 05:20:53
Message: <53106305$1@news.povray.org>
Le 28/02/2014 09:28, Orchid Win7 v1 a écrit :

>>> Not that VS is perfect, of course. Yesterday it gave me the dreaded
>>> C2512 error: "no appropriate default constructor available".
>>
>> Again, I'd have to see an actual example...
> 
>   struct Side
>   {
>     Pattern & Pattern;
>     Pattern::iterator & Iterator;
>   }
> 
>   struct State
>   {
>     Side & LeftSide;
>     Side & RightSide;
>     std::stringstream Buffer;
>     bool Success;
>   }
> 
> Every single line that declares a State variable gives me C2512. As you
> can see, I clearly *have not* defined any constructors, so that isn't
> the reason for a default constructor not existing.

But the compiler is unable to generate the default constructor (no
parameter) when some fields are references: they cannot be nullptr, and
they cannot be changed after the constructor, so what would be their
default value ?
By using reference as fields, you disabled the default implicit
constructor. It's your responsibility to now provides one, if you want it.



> I didn't mean references specifically. I just meant the entire language.
> Nobody would try to claim that C++ is small or simple or free of
> surprises. For example,
> 
>    struct Side
>    {
>      Pattern & ThePattern;
>      Side(Pattern p) : ThePattern(p) {}
>    }
> 
> Guess what? This segfaults when I run it. *You* probably see the problem
> immediately, but it took me 24 hours to figure out that there's a single
> missing character there...

two missing characters ? ;& ?
the ; after the last }.
the & in the constructor (Side(Pattern& p) ).

> 
> Today it's references. Last time it was
> 
>   catch (std::exception e)
>   {
>     std::cout << e.what();
>   }
> 
> which *always* says std::exception, even if that wasn't the exception
> thrown. The time before that, it was a memory leak due to an (empty)
> destructor not being virtual. There's so many buts and gotchas. And
> they're not the sort of thing where your program gives you the wrong
> answer; they're the sort of thing where you have a native crash and
> you're left utterly bewildered as to how the *hell* to discover what the
> problem was...

catch should use reference & const, to avoid copy constructor with
implicit upper-casting (that's the reason of the reference) and save
some time on exit of the block (that's the const).

catch(const std::exception & e)



-- 
Just because nobody complains does not mean all parachutes are perfect.


Post a reply to this message

From: Lars R 
Subject: Re: Undirected ramblings on C++
Date: 28 Feb 2014 06:54:23
Message: <531078ef$1@news.povray.org>
> I didn't mean references specifically. I just meant the entire language.
> Nobody would try to claim that C++ is small or simple or free of
> surprises. For example,
> 
>    struct Side
>    {
>      Pattern & ThePattern;
>      Side(Pattern p) : ThePattern(p) {}
>    }
> 
> Guess what? This segfaults when I run it. *You* probably see the problem
> immediately, but it took me 24 hours to figure out that there's a single
> missing character there...

Hence every compiler is able to emit a - more or less (depends on the
compiler you use) helpful - warning here.

So it is a good idea to compile always with a high warning level and you
should respect the emitted warnings.

> 
> Today it's references. Last time it was
> 
>   catch (std::exception e)
>   {
>     std::cout << e.what();
>   }

Even better: I wrote code like this:

   if(error)
   {
       std::runtime_error("XY went wrong");
   }

but no exception occured, because ... I forgot to _throw_ the exception. :-)

Lars R.


Post a reply to this message

From: Warp
Subject: Re: Undirected ramblings on C++
Date: 28 Feb 2014 09:16:52
Message: <53109a54@news.povray.org>
Orchid Win7 v1 <voi### [at] devnull> wrote:
>    struct Side
>    {
>      Pattern & Pattern;
>      Pattern::iterator Iterator;
>    }

I think you are misunderstanding what C++ references are. They are *not*
like Java references.

While internally references might be pointers, you should stop thinking
about them as such. As I said in my previous post, references are
effectively "aliases". In other words, a name that's an alias to an
object.

References must always be initialized to something and they cannot be
later changed to be an alias to something else. You can't have "null
references", nor uninitialized references.

While it's possible to have a reference as a member of a struct/class,
it's seldom useful. (There *are* some cases where it can be useful, but
it tends to be rare.) The reference must always be initialized, and it
can never be changed again. The former means that if you have a reference
member you have to write a constructor that initializes it. The latter
means that the class becomes non-assignable.

You are clearly trying to use references to make something like a
list/tree node. References cannot really be used for that in a sensible
manner (because as said the node becomes non-assignable and you can't
have "null references".) Such nodes are usually done with pointers instead.

As you should be well aware, you shouldn't start messing with pointers
in C++ unless you know what you are doing.

Also references can be misused. C++ is not gargabe-collected. It's not
guaranteed that the object that the reference is pointing to will remain
for as long as the reference does. (For example returning a reference to
a local object is possible, but undefined behavior. Don't do things like
that. Your program will just crash.)

If you can, use one of the standard library data containers. Writing your
own dynamic data container is error-prone if you don't have enough C++
experience.

> Every single line that declares a State variable gives me C2512. As you 
> can see, I clearly *have not* defined any constructors, so that isn't 
> the reason for a default constructor not existing.

The compiler cannot create a constructor because it doesn't know what
the reference should be initialized with.

Your fundamental problem is that you are trying to use references for
something they aren't meant for.

> So what you're saying is, a reference is a pointer where you can't ever 
> change the *address* it points to, but you can change what's *at* that 
> address?

It may be like that inside, but you should really just think of it as an
"alias" of the thing it's referring to. Whatever you do to the reference
you are doing to the original object.

> Does that also mean that assigning one vector to another actually 
> *copies* the entire vector? As in, a deep copy??

Like all standard data containers, they are handled by value. Assigning
one container object to another makes a deep copy.

This is not Java.

> I didn't mean references specifically. I just meant the entire language. 
> Nobody would try to claim that C++ is small or simple or free of 
> surprises. For example,

>     struct Side
>     {
>       Pattern & ThePattern;
>       Side(Pattern p) : ThePattern(p) {}
>     }

You should understand what's happening here.

The constructor is taking an object *by value*, which means that inside
the constructor 'p' is a temporary object (which will disappear when
the constructor ends.) You are then making 'ThePattern' a reference to
said temporary value. Then the constructor ends and... 'ThePattern' refers
to a non-existeng object. Crash.

You seem to be programming this like it were Java. C++ isn't.

Try to stop using references or pointers if you can. If you can't, then
try to use the standard data containers. If you absolutely *must* make
your own dynamic data container... well, you are going to make errors.

Does 'ThePattern' need to point to some other object, or can it simply
contain a *copy* of that object? If it can contain a copy, then make it
a non-reference. Then 'p' will be simply copied to it, and everything will
be fine and dandy.

> Today it's references. Last time it was

>    catch (std::exception e)
>    {
>      std::cout << e.what();
>    }

> which *always* says std::exception, even if that wasn't the exception 
> thrown.

I don't understand where you are getting at.

> The time before that, it was a memory leak due to an (empty) 
> destructor not being virtual.

I think one of the major problems you are having is that you insist in
allocating things dynamically and having pointers to them (instead of
using eg. smart pointers or just using the standard data containers.)

I code in C++ almost every day as my payjob. I write thousands and thousands
of likes of C++ code every year. Do you know when was the last time I wrote
the keywords 'new' or 'delete'? I don't even remember. It must have been
years.

A surprising amount of problems can be solved without ever writing a
single 'new' or 'delete', or having dangerous raw pointers pointing to
stuff. Most things can be handled by value, and 99% of dynamic data
managing can be used by using purely the standard data containers.

-- 
                                                          - Warp


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: Undirected ramblings on C++
Date: 28 Feb 2014 14:16:30
Message: <5310e08e@news.povray.org>
On 28/02/2014 02:16 PM, Warp wrote:
> Orchid Win7 v1<voi### [at] devnull>  wrote:
>>     struct Side
>>     {
>>       Pattern&  Pattern;
>>       Pattern::iterator Iterator;
>>     }
>
> I think you are misunderstanding what C++ references are.

Perhaps.

Basically, last time I read a book on C++, it said to never use pointers 
and always use references. So that's what I did. (And it worked - 
eventually. It just wasn't particularly easy...)

> You are clearly trying to use references to make something like a
> list/tree node. References cannot really be used for that in a sensible
> manner (because as said the node becomes non-assignable and you can't
> have "null references".) Such nodes are usually done with pointers instead.

Let me explain what I was *actually* trying to do...

I'm using an iterator to keep track of where I am in a collection. 
("Pattern" is actually a trivial alias to std::vector.) But as soon as 
you value-copy a container, all the iterators suddenly stop being valid. 
Ergo, I have to somehow avoid copying the vector at any cost.

What I would *actually* like to do is just throw iterators around. 
However, for reasons beyond my comprehension, nobody thought to include 
an "is_at_end()" method in the standard iterators. So without access to 
the original container, it's impossible to know if you've reached the 
end. If it weren't for this annoying detail, I wouldn't need references 
at all!

...well, OK, maybe I would. Because the whole *point* of the code I'm 
writing is that you call some function, passing a bunch of iterators, 
and when that function returns, the iterators have moved. That's not 
going to work if you pass iterators by value. (And yet, when I started 
searching the Internet, everybody seemed to think having a pointer to an 
iterator is 100% guaranteed to be a bug...)

> As you should be well aware, you shouldn't start messing with pointers
> in C++ unless you know what you are doing.

In the one place where I had to do that, it made me really nervous...

>> Every single line that declares a State variable gives me C2512. As you
>> can see, I clearly *have not* defined any constructors, so that isn't
>> the reason for a default constructor not existing.
>
> The compiler cannot create a constructor because it doesn't know what
> the reference should be initialized with.

I figured that out eventually. But it would have been nice if the 
*compiler* could have told me that!

>> Does that also mean that assigning one vector to another actually
>> *copies* the entire vector? As in, a deep copy??
>
> Like all standard data containers, they are handled by value. Assigning
> one container object to another makes a deep copy.

I always find it slightly surprising when C++ actually does stuff for 
you automatically. Everything seems to manual most of the time...

>> I didn't mean references specifically. I just meant the entire language.
>> Nobody would try to claim that C++ is small or simple or free of
>> surprises. For example,
>
>>      struct Side
>>      {
>>        Pattern&  ThePattern;
>>        Side(Pattern p) : ThePattern(p) {}
>>      }
>
> You should understand what's happening here.
>
> The constructor is taking an object *by value*, which means that inside
> the constructor 'p' is a temporary object (which will disappear when
> the constructor ends.) You are then making 'ThePattern' a reference to
> said temporary value. Then the constructor ends and... 'ThePattern' refers
> to a non-existeng object. Crash.

Yeah. I figured that out eventually. Not, of course, that you can ask 
the IDE to trap a segfault and pop up the line of code it was trying to 
run when the crash happened. I had to laboriously step through the code 
line by line until I discovered the problem.

> You seem to be programming this like it were Java. C++ isn't.

It would be more accurate to say "like it were C#".

> Try to stop using references or pointers if you can.

It would certainly be simpler if I could find a way to do that...

> Does 'ThePattern' need to point to some other object, or can it simply
> contain a *copy* of that object?

As I say, copying it stops all the iterators working.

>> Today it's references. Last time it was
>
>>     catch (std::exception e)
>>     {
>>       std::cout<<  e.what();
>>     }
>
>> which *always* says std::exception, even if that wasn't the exception
>> thrown.
>
> I don't understand where you are getting at.

Apparently you have to say "std::exception & e", otherwise whatever the 
exception was gets type-cast to a plain std::exception. (In particular, 
I was throwing std::runtime_error with an explanatory message, and 
tearing my hair out trying to figure out why the hell I can't see the 
message in the debug logs...)

>> The time before that, it was a memory leak due to an (empty)
>> destructor not being virtual.
>
> I think one of the major problems you are having is that you insist in
> allocating things dynamically and having pointers to them (instead of
> using eg. smart pointers or just using the standard data containers.)

The memory leak was due to some code that does actual run-time 
polymorphism. As I understand it, it's impossible to do dynamic dispatch 
in C++ without pointers.

> I code in C++ almost every day as my payjob. I write thousands and thousands
> of likes of C++ code every year. Do you know when was the last time I wrote
> the keywords 'new' or 'delete'? I don't even remember. It must have been
> years.

The code I'm fiddling with today doesn't contain *any* dynamic 
allocation at all. I'm merely trying to use references to avoid copying 
stuff, to keep iterators valid, and to allow a function to alter 
variables in the caller (i.e., "out parameters").



As an amusing aside, the other day I got to read some code where a guy 
did the opposite of what you accuse me of: he wrote C# as if it was C++. 
It was ugly! I especially enjoyed how EVERY SINGLE CLASS had an explicit 
destructor like this:

   public class Foo
   {
     private Bar _bar1, _bar2, _bar3;

     ...

     public ~Foo()
     {
       // Set fields to NULL to let the garbage collector know that
       // the memory can be reclaimed.
       _bar1 = null;
       _bar2 = null;
       _bar3 = null;
     }

...um, yeah, I'm not sure you're understanding this whole "automatic 
garbage collection" idea. :-P If this destructor ever runs, then it is 
highly likely that the fields you're nulling out have *already* been 
garbage collected! In fact, ironically, by writing an explicit 
destructor, you're actually keeping the object alive *longer*!

(In C#, any object that has a destructor gets added to a special list, 
and the destructor gets run on the *next* GC sweep. So normal objects 
get collected in one sweep, objects with a destructor take two 
consecutive GC sweeps to reclaim. Oops!)

In short, this code does the *opposite* of what the comment claims. If I 
just saw the code, I'd be puzzled. But the comment displays a 
fundamental misunderstanding of how the language actually works...


Post a reply to this message

Goto Latest 10 Messages Next 3 Messages >>>

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.