Wednesday, August 10, 2016

Digest for comp.lang.c++@googlegroups.com - 25 updates in 2 topics

Melzzzzz <mel@zzzzz.com>: Aug 10 01:27AM +0200

On Wed, 10 Aug 2016 00:20:43 +0100
 
> It is not really a problem to write classes this way. I am relaxed
> about it. You very soon get used to it.
 
Well, I'll live with it, just I am spoiled by Rust ;)
red floyd <no.spam@its.invalid>: Aug 09 04:29PM -0700

On 8/9/2016 2:29 PM, Melzzzzz wrote:
> destructor
> [bmaxa@maxa-pc examples]$
 
> Is this defect, and what is point of moving around, if not?
 
No, it's not a defect.
 
You have
* A constructed
* B move constructed
* B destructed
* A destructed
red floyd <no.spam@its.invalid>: Aug 09 04:31PM -0700

Never mind. I thought he was asking why the move constructor destroyed
the moved object.
"Öö Tiib" <ootiib@hot.ee>: Aug 09 04:49PM -0700

On Wednesday, 10 August 2016 01:57:53 UTC+3, Melzzzzz wrote:
> > wise to design the class so that it can still be assigned to after the
> > move.
 
> It looks to me like half baked solution.
 
BINGO! C++ is never fully baked solution. It is always just a tool-set
and materials from what *you* can make the stove, dough and other
things that you may be think you need for baking and have your best
baked solution. Additionally it is assumed that you are pyromaniac,
aren't you? So there is always some bear traps with TNT in every
component of C++.
Paavo Helde <myfirstname@osa.pri.ee>: Aug 10 02:59AM +0300

On 10.08.2016 1:56, Melzzzzz wrote:
 
> That also means that there is unnecessary code for maintaining state
> and also run time errors in case that object is moved twice...
> (what one should do if constructing from already moved object?)
 
As the object is still in a valid state, it can be freely moved from
again, and one typically gets a copy of the empty/sentinel value (an
empty string, for example).
 
> moved object is used after move (except assignment). Also compiler
> doesn't call destructors on moved objects so there is no need to worry
> about that.
 
So the house-keeping is essentially done by Rust compiler. This is
another ideology which might work as well. It's just not in the spirit
of C++ (as it seems to take away some ways to shoot one's legs off ;-)
(together with some loss of control and flexibility)).
 
Just for curiosity, what does Rust do when an object is moved-from in
one code branch and not in another? A compiler error?
 
Cheers
Paavo
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Aug 09 05:19PM -0700

What does this syntax mean?
 
A(A && moved) {
/* code here */
}
 
I've never seen it before.
 
Best regards,
Rick C. Hodgin
Melzzzzz <mel@zzzzz.com>: Aug 10 02:37AM +0200

On Wed, 10 Aug 2016 02:59:10 +0300
 
> Just for curiosity, what does Rust do when an object is moved-from in
> one code branch and not in another? A compiler error?
 
I don't understand? In Rust everything is moved by default. That is if
compiler finds that value is moved it always complaints if there is
other place where value is used.
In such cases, one should make copy of value , which is in Rust
implementing Clone trait and providing clone function.
Of course, there is also Copy trait (derived from Clone) if calling
clone is not convenient.
 
One is not required to implement Clone as there is #[derive(Clone)]
directive for automatic derivation, inspired by Haskell.
Nobody <nobody@nowhere.invalid>: Aug 10 03:48AM +0100

On Tue, 09 Aug 2016 17:19:21 -0700, Rick C. Hodgin wrote:
 
> /* code here */
> }
 
> I've never seen it before.
 
It's a move constructor.
 
A&& is an rvalue reference, introduced in C++11.
 
Basically, move constructors allow you to avoid deep-copying an object
that's about to be destroyed or overwritten. The move constructor can
just steal any dynamically-allocated data from "moved" rather than copying
it.
woodbrian77@gmail.com: Aug 09 09:03PM -0700

On Tuesday, August 9, 2016 at 9:48:48 PM UTC-5, Nobody wrote:
 
> Basically, move constructors allow you to avoid deep-copying an object
> that's about to be destroyed or overwritten. The move constructor can
> just steal any dynamically-allocated data from "moved" rather than copying
 
I'd say "adopt" rather than "just steal".
 
"Adopt" is shorter and the word "just" before
"steal" makes stealing sound like a small thing.
 
 
"There are four character types among people. One who says,
'What's mine is mine and what's yours is yours' is of
average character, and some say, this is the character of Sodom.
[One who says] 'What's mine is yours and what's yours is mine'
is unlearned (lit., [of] the people of the land).
[One who says] 'What's mine is yours and what's yours is yours'
is pious.
[One who says] 'What's yours is mine and what's mine is mine'
is wicked."
 
http://torah.org/learning/pirkei-avos-chapter5-13/
 
> it.
 
Brian
Ebenezer Enterprises
http://webEbenezer.net
"Öö Tiib" <ootiib@hot.ee>: Aug 10 12:32AM -0700

On Wednesday, 10 August 2016 03:37:32 UTC+3, Melzzzzz wrote:
 
> I don't understand? In Rust everything is moved by default. That is if
> compiler finds that value is moved it always complaints if there is
> other place where value is used.
 
It is possible to make code where proof that moved value is not used
can take very long time. Compiler can't hang on such code. So there must
be situation when it is uncertain. Now at that point it is interesting
if Rust's compiler does reject code when it can prove that moved value
is used or it does reject code when it can not prove that used value is
not moved or you don't know what it does.
David Brown <david.brown@hesbynett.no>: Aug 10 10:14AM +0200

On 10/08/16 02:19, Rick C. Hodgin wrote:
> /* code here */
> }
 
> I've never seen it before.
 
It is almost always written "A&& " rather than "A && ", just as "A&" is
used for a lvalue reference (the kind C++ has always supported) rather
than writing "A &". I certainly thought it looked strange with the
extra space.
 
rvalue references are new to C++11. They let you get a reference to
something that is anonymous or temporary, and let you "move" data around
rather than copying it. In particular, if you have an object that owns
some data or resource, and you "move" it somewhere else (such as into a
function), then you move ownership - the called function becomes
responsible for the object.
 
<http://thbecker.net/articles/rvalue_references/section_01.html>
<http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html>
<https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers>
 
rvalue references are somewhat hard to grasp - they are one of the
hardest new features of C++11. But they can make a big difference to
the efficiency of some kinds of code, and are therefore useful when
making class libraries. However, if you are just using classes, you can
use something like the unique_ptr<T> classes without understanding the
"magic" behind the scenes that make them work.
David Brown <david.brown@hesbynett.no>: Aug 10 10:24AM +0200

>> that's about to be destroyed or overwritten. The move constructor can
>> just steal any dynamically-allocated data from "moved" rather than copying
 
> I'd say "adopt" rather than "just steal".
 
"Adopt" is a better word for this than "steal", but that is because
during a "move" the source actively gives the data to the destination,
and the destination adopts responsibility for the data and resources.
 
Trying to apply human morality to programming terms makes it look like
you don't understand morality, and you don't understand programming.
/Programmers/ can be moral or amoral - programs cannot.
Melzzzzz <mel@zzzzz.com>: Aug 10 11:04AM +0200

On Wed, 10 Aug 2016 00:32:42 -0700 (PDT)
> interesting if Rust's compiler does reject code when it can prove
> that moved value is used or it does reject code when it can not prove
> that used value is not moved or you don't know what it does.
 
I think that Rust compiler just complains if it sees any code path
where value is moved regardless.
"Öö Tiib" <ootiib@hot.ee>: Aug 10 03:08AM -0700

On Wednesday, 10 August 2016 12:04:40 UTC+3, Melzzzzz wrote:
> > that used value is not moved or you don't know what it does.
 
> I think that Rust compiler just complains if it sees any code path
> where value is moved regardless.
 
So you think that following code will be rejected by Rust?
I write just pseudo-code, I don't know Rust. Comment "..."
means code that does not deal with neither 'condition' nor 'variable':
 
if ( condition )
{
// ...
 
move( variable );
 
// ...
}

// ...
 
unless ( condition )
{
// ...
 
use( variable ); // <- we can't reach that with moved 'variable'
 
// ...
}
"Öö Tiib" <ootiib@hot.ee>: Aug 10 03:11AM -0700

On Wednesday, 10 August 2016 11:24:42 UTC+3, David Brown wrote:
 
> Trying to apply human morality to programming terms makes it look like
> you don't understand morality, and you don't understand programming.
> /Programmers/ can be moral or amoral - programs cannot.
 
That can be viewed as existential risk for humankind. Stephen Hawking
talks about it:
http://www.dailymail.co.uk/sciencetech/article-3406751/Hawking-Threats-human-survival-likely-new-science.html
Some even research that risk:
http://cser.org/research/current-projects/
IOW ... depends how to look at if ... if it is a problem, or if it is
misunderstanding.
Melzzzzz <mel@zzzzz.com>: Aug 10 12:24PM +0200

On Wed, 10 Aug 2016 03:08:28 -0700 (PDT)
> 'variable'
 
> // ...
> }
 
[bmaxa@maxa-pc examples]$ cat moved.rs
struct A;
impl Drop for A{
fn drop(&mut self) {
println!("destructor");
}
}
 
fn main() {
let a = A;
if false {
let b = a;
} else {
}
if false {
let c = a;
}
}
[bmaxa@maxa-pc examples]$ rustc moved.rs
error[E0382]: use of moved value: `a`
--> moved.rs:15:13
|
11 | let b = a;
| - value moved here
...
15 | let c = a;
| ^ value used here after move
|
= note: move occurs because `a` has type `A`, which does not implement the `Copy` trait
 
error: aborting due to previous error
Daniel <danielaparker@gmail.com>: Aug 10 06:47AM -0700

On Wednesday, August 10, 2016 at 4:24:42 AM UTC-4, David Brown wrote:
 
> /Programmers/ can be moral or amoral - programs cannot.
 
Sure they can. A deep learning program could be taught to be moral, with Old
Testament training sets. After training and testing, it could be set to
control sensors that activated weapons systems.
 
Daniel
 
10 When thou comest nigh unto a city to fight against it, then proclaim peace
unto it....
 
13 And when the Lord thy God hath delivered it into thine hands, thou shalt
smite every male thereof with the edge of the sword:
 
14 But the women, and the little ones, and the cattle, and all that is in the
city, even all the spoil thereof, shalt thou take unto thyself; and thou shalt
eat the spoil of thine enemies, which the Lord thy God hath given thee.
 
15 Thus shalt thou do unto all the cities which are very far off from thee,
which are not of the cities of these nations.
 
16 But of the cities of these people, which the Lord thy God doth give thee
for an inheritance, thou shalt save alive nothing that breatheth:
 
Deuteronomy 20:10-16
 
15 And Moses said unto them, Have ye saved all the women alive?
 
16 Behold, these caused the children of Israel, through the counsel of Balaam,
to commit trespass against the Lord in the matter of Peor, and there was a
plague among the congregation of the Lord.
 
17 Now therefore kill every male among the little ones, and kill every woman
that hath known man by lying with him.
 
18 But all the women children, that have not known a man by lying with him,
keep alive for yourselves.
 
Numbers 31:15-18
Melzzzzz <mel@zzzzz.com>: Aug 10 03:49PM +0200

On Wed, 10 Aug 2016 06:47:19 -0700 (PDT)
 
> Sure they can. A deep learning program could be taught to be moral,
> with Old Testament training sets. After training and testing, it
> could be set to control sensors that activated weapons systems.
 
Could it be said that malware is amoral?
"Adam C. Emerson" <azure@fox.blue>: Aug 10 05:40PM

> clone is not convenient.
 
> One is not required to implement Clone as there is #[derive(Clone)]
> directive for automatic derivation, inspired by Haskell.
 
I think the problem you're having is that you assume that C++ 'move'
construction and assignment are analogous to Rust's notion of
ownership. Rust's ownership is a compile time property managing
lifetimes and keeping track of when data can be safely disposed of.
 
In C++, 'move' isn't really an operation. You have a special kind of
reference (an rvalue reference) and you can overload functions,
including the constructor and assignment operators, to behave
differently when they receive an rvalue reference.
 
The rvalue overload overloads of the constructor and assignment
operators are traditionally called 'move' constructors and 'move'
assignment operators. Both are allowed to do whatever you want, though
if you write some weird move constructor you will probably have great
sorrow and heaps of infelicity when you go to use your class with the
standard library or other code.
 
To be useful and integrate well with the rest of the language, the
move constructor MUST leave the 'moved-from' object in a valid
state. It doesn't have to be 'empty' it just has to be a valid
object. You will generally only bother writing a move constructor if
you can get some use out of it. So, say, if your class contains a
pointer to allocated memory, you might copy the pointer to the new
object and null it in the old (moved-from) object.
 
C++'s idea of movement makes no sense at all in Rust, since in C++ you
have to manage your own memory and manage lifetimes on your own and
all that other stuff. So, while they might not be what you're used to
or what would make sense in other languages, move semantics make sense
within the general shape of C++ as a language and as a set of
practices (like RAII).
Melzzzzz <mel@zzzzz.com>: Aug 10 08:08PM +0200

On Wed, 10 Aug 2016 17:40:29 -0000 (UTC)
 
> C++'s idea of movement makes no sense at all in Rust, since in C++ you
> have to manage your own memory and manage lifetimes on your own and
> all that other stuff.
 
Rust is same as C++ regarding memory management. It's just that
unique_ptr is build into language... Box::new(Type) allocates on heap
and returns unique_ptr. There are also structs like Rc which are
actually shared_ptr. Resources are managed by RAII. Actually
Rust in the beginning had GC but that was later ditched from language,
I guess because of performance reasons...
Melzzzzz <mel@zzzzz.com>: Aug 10 08:15PM +0200

On Wed, 10 Aug 2016 20:08:28 +0200
 
> Box::new(Type) allocates on heap
 
No, Box::new(data), as it is just like any other function...
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Aug 10 12:23AM +0100

On 10/08/2016 00:02, Daniel wrote:
 
>> It was necessary to do that to ensure that a key cannot be changed once
>> added to the binary search tree.
 
> No. That's an interface issue, not an implementation issue.
 
It is both.
 
 
> There is no problem if value_type is defined as a type having a key() accessor
> that is non-modifying.
 
You cannot allow the key to be changed by allowing access to it hence it
must be const.
 
> might change the key. If it's a perverse class implementer you're worried
> about, well, he could always remove a tree node and replace it with a new one
> with a different key, const key or not.
 
You don't get it: if a key in a binary search tree is changed the tree
can become corrupt and invalid.
 
 
> Anyway, this is, while regrettable, unable to be changed.
 
It isn't regrettable as it is the correct design.
 
/Flibble
Daniel <danielaparker@gmail.com>: Aug 09 05:03PM -0700

On Tuesday, August 9, 2016 at 7:23:42 PM UTC-4, Mr Flibble wrote:
 
 
> if a key in a binary search tree is changed the tree
> can become corrupt and invalid.
 
Obviously. Nobody has suggested otherwise. In fact, that's true of
associative containers generally.
 
> It isn't regrettable as it is the correct design.
 
What you're saying is that the standard requirement for associate containers, that they _must_ store key value pairs in std::pair<const Key,mapped_typed> value types, and allow no other internal physical representation, is the correct design. That doesn't work for btrees, where value types have to be shuffled between blocks when re-balancing, and it doesn't work for b+ trees, where keys and values are stored separately, and it doesn't work for sequences of key value pairs.
 
All of these associative data structures have the logical requirement that the
key doesn't change, but a whole class of them can't use std::pair<const
Key,mapped_typed> for physical storage. The interface for associative
containers shouldn't dictate that they must. The fact that it does is
regrettable, because a whole class of associative containers that have
desirable characteristics can't participate in generic algorithms.
 
And it was unnecessary.
 
Best regards,
Daniel
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Aug 09 07:13PM -0500

> regrettable, because a whole class of associative containers that have
> desirable characteristics can't participate in generic algorithms.
 
> And it was unnecessary.
 
It was not unnecessary for map as it is the correct design for map.
 
/Flibble
Daniel <danielaparker@gmail.com>: Aug 09 06:00PM -0700

On Tuesday, August 9, 2016 at 8:13:24 PM UTC-4, Mr Flibble wrote:
 
> It was not unnecessary for map as it is the correct design for map.
 
I don't think so :-)
 
iterator and const_iterator are not required to be particular types, just types that have certain properties. Similarly, there was no reason to require that value_type be a particular type (std::pair<const key_type,mapped_type>), as with the iterator types, it would have been enough to specify that it have certain properties (an accessor for a key, an accessor and a modifier for a value.)
 
That would have allowed a larger class of map-like containers to be introduced and be used interchangeably, much as it is already possible to use a wide class of sequence containers interchangeably.
 
Best regards,
Daniel
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: