• fstreams

    From Stefan Ram@3:633/280.2 to All on Thu Mar 28 02:11:31 2024
    This (barring typos) is from a book by Bjarne:

    int main()
    {
    string from, to; /* get source and target file names */
    cin >> from >> to;

    ifstream is( from.c_str() ); /* open input stream */
    ofstream os( to.c_str() ); /* open output stream */

    istream_iterator<string> ii(is); /* make input iterator for stream */
    istream_iterator<string> eos; /* input sentinel */
    ostream_iterator<string> oo(os,"\n"); /* make out it. for stream */

    set<string> b(ii, eos); /* b is a set initialized from input */
    copy(b.begin(), b.end(), oo); /* copy buffer to output */ }

    So, is this good style not checking the stream states after opening?

    IIRC, out of the box those streams will not throw an exception
    when they cannot open.

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: Stefan Ram (3:633/280.2@fidonet)
  • From Sam@3:633/280.2 to All on Thu Mar 28 08:32:12 2024
    Stefan Ram writes:

    This (barring typos) is from a book by Bjarne:

    int main()
    {
    string from, to; /* get source and target file names */
    cin >> from >> to;

    ifstream is( from.c_str() ); /* open input stream */
    ofstream os( to.c_str() ); /* open output stream */

    istream_iterator<string> ii(is); /* make input iterator for stream */
    istream_iterator<string> eos; /* input sentinel */
    ostream_iterator<string> oo(os,"\n"); /* make out it. for stream */

    set<string> b(ii, eos); /* b is a set initialized from input */
    copy(b.begin(), b.end(), oo); /* copy buffer to output */ }

    So, is this good style not checking the stream states after opening?

    What's the purpose of the above example? Looks to me like it's demonstrating some basic stream operation, so error checking is immaterial. I would think that there'll be a separate discussion about error checking where this topic would be discussed.

    Common sense dictates that: if it's expected to clearly report any errors then the appropriate logic would be added. But if a missing file or an empty error should have functionally identical repercussions as an empty file then there's little to be gained by an extra check.



    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Scott Lurndal@3:633/280.2 to All on Thu Mar 28 09:35:22 2024
    Reply-To: slp53@pacbell.net

    Sam <sam@email-scan.com> writes:
    Stefan Ram writes:

    This (barring typos) is from a book by Bjarne:

    int main()
    {
    string from, to; /* get source and target file names */
    cin >> from >> to;

    ifstream is( from.c_str() ); /* open input stream */
    ofstream os( to.c_str() ); /* open output stream */

    istream_iterator<string> ii(is); /* make input iterator for stream */
    istream_iterator<string> eos; /* input sentinel */
    ostream_iterator<string> oo(os,"\n"); /* make out it. for stream */

    set<string> b(ii, eos); /* b is a set initialized from input */
    copy(b.begin(), b.end(), oo); /* copy buffer to output */ }

    So, is this good style not checking the stream states after opening?

    What's the purpose of the above example? Looks to me like it's demonstrating >some basic stream operation, so error checking is immaterial. I would think >that there'll be a separate discussion about error checking where this topic >would be discussed.

    It's not clear from which book Stefan found this example. It
    doesn't work correctly, however:

    $ cat a.cpp
    #include <string>
    #include <fstream>
    #include <iostream>
    #include <iterator>
    #include <set>

    using namespace std;

    int main()
    {
    string from, to; /* get source and target file names */
    cin >> from >> to;

    ifstream is( from.c_str() ); /* open input stream */
    ofstream os( to.c_str() ); /* open output stream */

    istream_iterator<string> ii(is); /* make input iterator for stream */
    istream_iterator<string> eos; /* input sentinel */
    ostream_iterator<string> oo(os,"\n"); /* make out it. for stream */

    set<string> b(ii, eos); /* b is a set initialized from input */
    copy(b.begin(), b.end(), oo); /* copy buffer to output */
    }

    $ ./a
    i.png
    j.png
    $ ls -l ?.png
    -rw-------. 1 scott scott 2413 Mar 27 13:58 i.png
    -rw-rw-r--. 1 scott scott 2411 Mar 27 15:27 j.png

    The output file is two bytes shorter than the input file.

    The generated code, even with -O2 is horrible, terrible, awful.

    0000000000400f90 <main>:
    400f90: 41 55 push %r13
    400f92: bf 00 31 60 00 mov $0x603100,%edi
    400f97: 41 54 push %r12
    400f99: 55 push %rbp
    400f9a: 53 push %rbx
    400f9b: 48 81 ec 38 05 00 00 sub $0x538,%rsp
    400fa2: 48 8d 74 24 10 lea 0x10(%rsp),%rsi
    400fa7: 48 c7 44 24 10 38 32 movq $0x603238,0x10(%rsp)
    400fae: 60 00
    400fb0: 48 c7 44 24 20 38 32 movq $0x603238,0x20(%rsp)
    400fb7: 60 00
    400fb9: e8 d2 fe ff ff callq 400e90 <std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)@plt>
    400fbe: 48 8d 74 24 20 lea 0x20(%rsp),%rsi
    400fc3: 48 89 c7 mov %rax,%rdi
    400fc6: e8 c5 fe ff ff callq 400e90 <std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)@plt>
    400fcb: 4c 8d a4 24 20 03 00 lea 0x320(%rsp),%r12
    400fd2: 00
    400fd3: 48 8b 74 24 10 mov 0x10(%rsp),%rsi
    400fd8: ba 08 00 00 00 mov $0x8,%edx
    400fdd: 4c 89 e7 mov %r12,%rdi
    400fe0: e8 2b ff ff ff callq 400f10 <std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(char const*, std::_Ios_Openmode)@plt>
    400fe5: 48 8b 74 24 20 mov 0x20(%rsp),%rsi
    400fea: 48 8d bc 24 20 01 00 lea 0x120(%rsp),%rdi
    400ff1: 00
    400ff2: ba 30 00 00 00 mov $0x30,%edx
    400ff7: e8 24 ff ff ff callq 400f20 <std::basic_ofstream<char, std::char_traits<char> >::basic_ofstream(char const*, std::_Ios_Openmode)@plt>
    400ffc: 48 8b 84 24 20 03 00 mov 0x320(%rsp),%rax
    401003: 00
    401004: 4c 89 64 24 30 mov %r12,0x30(%rsp)
    401009: 48 c7 44 24 38 38 32 movq $0x603238,0x38(%rsp)
    401010: 60 00
    401012: 48 8b 40 e8 mov -0x18(%rax),%rax
    401016: f6 84 04 40 03 00 00 testb $0x5,0x340(%rsp,%rax,1)
    40101d: 05
    40101e: 0f 84 6a 02 00 00 je 40128e <main+0x2fe>
    401024: c6 44 24 40 00 movb $0x0,0x40(%rsp)
    401029: 48 8d bc 24 98 00 00 lea 0x98(%rsp),%rdi
    401030: 00
    401031: 48 8d 74 24 58 lea 0x58(%rsp),%rsi
    401036: 48 c7 44 24 50 00 00 movq $0x0,0x50(%rsp)
    40103d: 00 00
    40103f: 48 c7 44 24 58 38 32 movq $0x603238,0x58(%rsp)
    401046: 60 00
    401048: c6 44 24 60 00 movb $0x0,0x60(%rsp)
    40104d: 48 c7 84 24 90 00 00 movq $0x0,0x90(%rsp)
    401054: 00 00 00 00 00
    401059: e8 02 fe ff ff callq 400e60 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&)@plt>
    40105e: 0f b6 44 24 60 movzbl 0x60(%rsp),%eax
    401063: 48 8d 7c 24 78 lea 0x78(%rsp),%rdi
    401068: 48 8d 74 24 38 lea 0x38(%rsp),%rsi
    40106d: 88 84 24 a0 00 00 00 mov %al,0xa0(%rsp)
    401074: 48 8b 44 24 30 mov 0x30(%rsp),%rax
    401079: 48 89 44 24 70 mov %rax,0x70(%rsp)
    40107e: e8 dd fd ff ff callq 400e60 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&)@plt>
    401083: 0f b6 44 24 40 movzbl 0x40(%rsp),%eax
    401088: 48 8d b4 24 98 00 00 lea 0x98(%rsp),%rsi
    40108f: 00
    40108f: 00
    401090: 48 8d bc 24 d8 00 00 lea 0xd8(%rsp),%rdi
    401097: 00
    401098: c7 84 24 f8 00 00 00 movl $0x0,0xf8(%rsp)
    40109f: 00 00 00 00
    4010a3: 48 c7 84 24 00 01 00 movq $0x0,0x100(%rsp)
    4010aa: 00 00 00 00 00
    4010af: 48 c7 84 24 18 01 00 movq $0x0,0x118(%rsp)
    4010b6: 00 00 00 00 00
    4010bb: 88 84 24 80 00 00 00 mov %al,0x80(%rsp)
    4010c2: 48 8d 84 24 f8 00 00 lea 0xf8(%rsp),%rax
    4010c9: 00
    4010ca: 48 89 84 24 08 01 00 mov %rax,0x108(%rsp)
    4010d1: 00
    4010d2: 48 89 84 24 10 01 00 mov %rax,0x110(%rsp)
    4010d9: 00
    4010da: 48 8b 84 24 90 00 00 mov 0x90(%rsp),%rax
    4010e1: 00
    4010e2: 48 89 84 24 d0 00 00 mov %rax,0xd0(%rsp)
    4010e9: 00
    4010ea: e8 71 fd ff ff callq 400e60 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&)@plt>
    4010ef: 0f b6 84 24 a0 00 00 movzbl 0xa0(%rsp),%eax
    4010f6: 00
    4010f7: 48 8d 74 24 78 lea 0x78(%rsp),%rsi
    4010fc: 48 8d bc 24 b8 00 00 lea 0xb8(%rsp),%rdi
    401103: 00
    401104: 88 84 24 e0 00 00 00 mov %al,0xe0(%rsp)
    40110b: 48 8b 44 24 70 mov 0x70(%rsp),%rax
    401110: 48 89 84 24 b0 00 00 mov %rax,0xb0(%rsp)
    401117: 00
    401118: e8 43 fd ff ff callq 400e60 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&)@plt>
    40111d: 0f b6 84 24 80 00 00 movzbl 0x80(%rsp),%eax
    401124: 00
    401125: 48 8d 94 24 d0 00 00 lea 0xd0(%rsp),%rdx
    40112c: 00
    40112d: 48 8d b4 24 b0 00 00 lea 0xb0(%rsp),%rsi
    401134: 00
    401135: 48 8d bc 24 f0 00 00 lea 0xf0(%rsp),%rdi
    40113c: 00
    40113d: 88 84 24 c0 00 00 00 mov %al,0xc0(%rsp)
    401144: e8 27 08 00 00 callq 401970 <void std::_Rb_tree<std::string, std::string, std::_Identity<std::string>, std::less<std::string>, std::allocator<std::string> >::_M_insert_unique<std::istream_iterator<std::string, char, std::char_traits<char>, long> >(std::istream_iterator<std::string, char, std::char_traits<char>, long>, std::istream_iterator<std::string, char, std::char_traits<char>, long>)>
    401149: 48 8b 84 24 b8 00 00 mov 0xb8(%rsp),%rax
    401150: 00
    401151: 4c 8d 6c 24 0f lea 0xf(%rsp),%r13
    401156: 48 8d ac 24 f8 00 00 lea 0xf8(%rsp),%rbp
    40115d: 00
    40115e: 4c 89 ee mov %r13,%rsi
    401161: 48 8d 78 e8 lea -0x18(%rax),%rdi
    401165: e8 a6 fc ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    40116a: 48 8b 84 24 d8 00 00 mov 0xd8(%rsp),%rax
    401171: 00
    401172: 48 8d b4 24 b0 00 00 lea 0xb0(%rsp),%rsi
    401179: 00
    40117a: 48 8d 78 e8 lea -0x18(%rax),%rdi
    40117e: e8 8d fc ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    401183: 48 8b 44 24 78 mov 0x78(%rsp),%rax
    401188: 48 8d b4 24 d0 00 00 lea 0xd0(%rsp),%rsi
    40118f: 00
    401190: 48 8d 78 e8 lea -0x18(%rax),%rdi
    401194: e8 77 fc ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    401199: 48 8b 84 24 98 00 00 mov 0x98(%rsp),%rax
    4011a0: 00
    4011a1: 48 8d b4 24 d0 00 00 lea 0xd0(%rsp),%rsi
    4011a8: 00
    4011a9: 48 8d 78 e8 lea -0x18(%rax),%rdi
    4011ad: e8 5e fc ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    4011b2: 48 8b 9c 24 08 01 00 mov 0x108(%rsp),%rbx
    4011b9: 00
    4011ba: 48 39 eb cmp %rbp,%rbx
    4011bd: 74 3d je 4011fc <main+0x26c>
    4011bf: 90 nop
    4011c0: 48 8b 73 20 mov 0x20(%rbx),%rsi
    4011c4: 48 8d bc 24 20 01 00 lea 0x120(%rsp),%rdi
    4011cb: 00
    4011cc: 48 8b 56 e8 mov -0x18(%rsi),%rdx
    4011d0: e8 0b fd ff ff callq 400ee0 <std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)@plt>
    4011d5: 48 8d bc 24 20 01 00 lea 0x120(%rsp),%rdi
    4011dc: 00
    4011dd: ba 01 00 00 00 mov $0x1,%edx
    4011e2: be b0 1b 40 00 mov $0x401bb0,%esi
    4011e7: e8 f4 fc ff ff callq 400ee0 <std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)@plt>
    4011ec: 48 89 df mov %rbx,%rdi
    4011ef: e8 bc fc ff ff callq 400eb0 <std::_Rb_tree_increment(std::_Rb_tree_node_base const*)@plt>
    4011f4: 48 39 e8 cmp %rbp,%rax
    4011f7: 48 89 c3 mov %rax,%rbx
    4011fa: 75 c4 jne 4011c0 <main+0x230>
    4011fc: 48 8b b4 24 00 01 00 mov 0x100(%rsp),%rsi
    401203: 00
    401204: 48 8d bc 24 f0 00 00 lea 0xf0(%rsp),%rdi
    40120b: 00
    40120c: e8 1f 03 00 00 callq 401530 <std::_Rb_tree<std::string, std::string, std::_Identity<std::string>, std::less<std::string>, std::allocator<std::string> >::_M_erase(std::_Rb_tree_node<std::string>*)>
    401211: 48 8b 44 24 58 mov 0x58(%rsp),%rax
    401216: 48 8d b4 24 d0 00 00 lea 0xd0(%rsp),%rsi
    40121d: 00
    40121e: 48 8d 78 e8 lea -0x18(%rax),%rdi
    401222: e8 e9 fb ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    401227: 48 8b 44 24 38 mov 0x38(%rsp),%rax
    40122c: 48 8d b4 24 d0 00 00 lea 0xd0(%rsp),%rsi
    401233: 00
    401234: 48 8d 78 e8 lea -0x18(%rax),%rdi
    401238: e8 d3 fb ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    40123d: 48 8d bc 24 20 01 00 lea 0x120(%rsp),%rdi
    401244: 00
    401245: e8 86 fc ff ff callq 400ed0 <std::basic_ofstream<char, std::char_traits<char> >::~basic_ofstream()@plt>
    40124a: 4c 89 e7 mov %r12,%rdi
    40124d: e8 6e fc ff ff callq 400ec0 <std::basic_ifstream<char, std::char_traits<char> >::~basic_ifstream()@plt>
    401252: 48 8b 44 24 20 mov 0x20(%rsp),%rax
    401257: 48 8d b4 24 d0 00 00 lea 0xd0(%rsp),%rsi
    40125e: 00
    40125f: 48 8d 78 e8 lea -0x18(%rax),%rdi
    401263: e8 a8 fb ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    401268: 48 8b 44 24 10 mov 0x10(%rsp),%rax
    40126d: 48 8d b4 24 d0 00 00 lea 0xd0(%rsp),%rsi
    401274: 00
    401275: 48 8d 78 e8 lea -0x18(%rax),%rdi
    401279: e8 92 fb ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    40127e: 48 81 c4 38 05 00 00 add $0x538,%rsp
    401285: 31 c0 xor %eax,%eax
    401287: 5b pop %rbx
    401288: 5d pop %rbp
    401289: 41 5c pop %r12
    40128b: 41 5d pop %r13
    40128d: c3 retq
    40128e: 48 8d 74 24 38 lea 0x38(%rsp),%rsi
    401293: 4c 89 e7 mov %r12,%rdi
    401296: c6 44 24 40 01 movb $0x1,0x40(%rsp)
    40129b: e8 f0 fb ff ff callq 400e90 <std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)@plt>
    4012a0: 48 8b 54 24 30 mov 0x30(%rsp),%rdx
    4012a5: 48 8b 02 mov (%rdx),%rax
    4012a8: 48 03 50 e8 add -0x18(%rax),%rdx
    4012ac: 31 c0 xor %eax,%eax
    4012ae: f6 42 20 05 testb $0x5,0x20(%rdx)
    4012b2: 48 0f 44 c2 cmove %rdx,%rax
    4012b6: 48 85 c0 test %rax,%rax
    4012b9: 0f 95 44 24 40 setne 0x40(%rsp)
    4012be: e9 66 fd ff ff jmpq 401029 <main+0x99>
    4012c3: 48 89 c3 mov %rax,%rbx
    4012c6: 48 8b 44 24 38 mov 0x38(%rsp),%rax
    4012cb: 48 8d 74 24 0f lea 0xf(%rsp),%rsi
    4012d0: 48 8d 78 e8 lea -0x18(%rax),%rdi
    4012d4: e8 37 fb ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    4012d9: 48 8d bc 24 20 01 00 lea 0x120(%rsp),%rdi
    4012e0: 00
    4012e1: e8 ea fb ff ff callq 400ed0 <std::basic_ofstream<char, std::char_traits<char> >::~basic_ofstream()@plt>
    4012e6: 4c 89 e7 mov %r12,%rdi
    4012e9: e8 d2 fb ff ff callq 400ec0 <std::basic_ifstream<char, std::char_traits<char> >::~basic_ifstream()@plt>
    4012ee: 48 8b 44 24 20 mov 0x20(%rsp),%rax
    4012f3: 48 8d 74 24 0e lea 0xe(%rsp),%rsi
    4012f8: 48 8d 78 e8 lea -0x18(%rax),%rdi
    4012fc: e8 0f fb ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    401301: 48 8b 44 24 10 mov 0x10(%rsp),%rax
    401306: 48 8d 74 24 0e lea 0xe(%rsp),%rsi
    40130b: 48 8d 78 e8 lea -0x18(%rax),%rdi
    40130f: e8 fc fa ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    401314: 48 89 df mov %rbx,%rdi
    401317: e8 64 fc ff ff callq 400f80 <_Unwind_Resume@plt>
    40131c: 48 8b b4 24 00 01 00 mov 0x100(%rsp),%rsi
    401323: 00
    401324: 48 8d bc 24 f0 00 00 lea 0xf0(%rsp),%rdi
    40132b: 00
    40132c: 48 89 c3 mov %rax,%rbx
    40132f: e8 fc 01 00 00 callq 401530 <std::_Rb_tree<std::string, std::string, std::_Identity<std::string>, std::less<std::string>, std::allocator<std::string> >::_M_erase(std::_Rb_tree_node<std::string>*)>
    401334: 48 8b 44 24 58 mov 0x58(%rsp),%rax
    401339: 4c 89 ee mov %r13,%rsi
    40133c: 48 8d 78 e8 lea -0x18(%rax),%rdi
    401340: e8 cb fa ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    401345: 48 8b 44 24 38 mov 0x38(%rsp),%rax
    40134a: 4c 89 ee mov %r13,%rsi
    40134d: 48 8d 78 e8 lea -0x18(%rax),%rdi
    401351: e8 ba fa ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    401356: eb 81 jmp 4012d9 <main+0x349>
    401358: 48 89 c3 mov %rax,%rbx
    40135b: 48 8b 84 24 b8 00 00 mov 0xb8(%rsp),%rax
    401362: 00
    401363: 4c 8d 6c 24 0f lea 0xf(%rsp),%r13
    401368: 4c 89 ee mov %r13,%rsi
    40136b: 48 8d 78 e8 lea -0x18(%rax),%rdi
    40136f: e8 9c fa ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    401374: 48 8b 84 24 d8 00 00 mov 0xd8(%rsp),%rax
    40137b: 00
    40137c: 4c 89 ee mov %r13,%rsi
    40137f: 48 8d 78 e8 lea -0x18(%rax),%rdi
    401383: e8 88 fa ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    401388: 48 8b b4 24 00 01 00 mov 0x100(%rsp),%rsi
    40138f: 00
    401390: 48 8d bc 24 f0 00 00 lea 0xf0(%rsp),%rdi
    401397: 00
    401398: e8 93 01 00 00 callq 401530 <std::_Rb_tree<std::string, std::string, std::_Identity<std::string>, std::less<std::string>, std::allocator<std::string> >::_M_erase(std::_Rb_tree_node<std::string>*)>
    40139d: 48 8b 44 24 78 mov 0x78(%rsp),%rax
    4013a2: 4c 89 ee mov %r13,%rsi
    4013a5: 48 8d 78 e8 lea -0x18(%rax),%rdi
    4013a9: e8 62 fa ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    4013ae: 48 8b 84 24 98 00 00 mov 0x98(%rsp),%rax
    4013b5: 00
    4013b6: 4c 89 ee mov %r13,%rsi
    4013b9: 48 8d 78 e8 lea -0x18(%rax),%rdi
    4013bd: e8 4e fa ff ff callq 400e10 <std::string::_Rep::_M_dispose(std::allocator<char> const&)@plt>
    4013c2: e9 6d ff ff ff jmpq 401334 <main+0x3a4>
    4013c7: 48 89 c3 mov %rax,%rbx
    4013ca: 4c 8d 6c 24 0f lea 0xf(%rsp),%r13
    4013cf: eb a3 jmp 401374 <main+0x3e4>
    4013d1: 48 89 c3 mov %rax,%rbx
    4013d4: 4c 8d 6c 24 0f lea 0xf(%rsp),%r13
    4013d9: eb ad jmp 401388 <main+0x3f8>
    4013db: 48 89 c3 mov %rax,%rbx
    4013de: 4c 8d 6c 24 0f lea 0xf(%rsp),%r13
    4013e3: eb c9 jmp 4013ae <main+0x41e>
    4013e5: 48 89 c3 mov %rax,%rbx
    4013e8: 4c 8d 6c 24 0f lea 0xf(%rsp),%r13
    4013ed: e9 42 ff ff ff jmpq 401334 <main+0x3a4>
    4013f2: 48 89 c3 mov %rax,%rbx
    4013f5: e9 ec fe ff ff jmpq 4012e6 <main+0x356>
    4013fa: 48 89 c3 mov %rax,%rbx
    4013fd: e9 ec fe ff ff jmpq 4012ee <main+0x35e>
    401402: 66 66 66 66 66 2e 0f data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
    401409: 1f 84 00 00 00 00 00


    Common sense dictates that: if it's expected to clearly report any errors >then the appropriate logic would be added. But if a missing file or an empty >error should have functionally identical repercussions as an empty file then >there's little to be gained by an extra check.

    Yes, if you run it and the first file doesn't exist, it just creates
    an empty output file with no error message.

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: UsenetServer - www.usenetserver.com (3:633/280.2@fidonet)
  • From Michael S@3:633/280.2 to All on Thu Mar 28 10:23:31 2024
    On Wed, 27 Mar 2024 22:35:22 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:


    The generated code, even with -O2 is horrible, terrible, awful.


    Why would you expect that such awfully designed library as C++
    iostream would generate anything but an awfull code?


    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Thu Mar 28 12:41:43 2024
    On 3/27/2024 4:23 PM, Michael S wrote:
    On Wed, 27 Mar 2024 22:35:22 GMT
    scott@slp53.sl.home (Scott Lurndal) wrote:


    The generated code, even with -O2 is horrible, terrible, awful.


    Why would you expect that such awfully designed library as C++
    iostream would generate anything but an awfull code?


    ;^o

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Stefan Ram@3:633/280.2 to All on Thu Mar 28 19:13:00 2024
    Sam <sam@email-scan.com> wrote or quoted:
    What's the purpose of the above example? Looks to me like it's demonstrating >some basic stream operation, so error checking is immaterial. I would think >that there'll be a separate discussion about error checking where this topic >would be discussed.

    It might have been to showcase sets.

    For my C++ tutorial, I want to have "canonical" examples of
    how to read and write files in C++ that can serve as "role
    models" (templates in the general sense) for code.

    I thought I could get the best example code from books by Bjarne.

    Now, I have asked a chatbot. Me,

    |Please show me code in C++ that opens a file and writes
    |"Hello" to it. The C++ version should be as modern as
    |possible and the program should have perfect error checking.

    ; the chatbot,

    |C++ Code to Write "Hello" to a File
    |
    |Here's a modern C++ code snippet that opens a file and writes
    |"Hello" to it, with robust error checking:
    |
    |cpp
    |
    |#include <iostream>
    |#include <fstream>
    |#include <filesystem>
    |
    |int main() {
    | try {
    | // Create the file path
    | std::filesystem::path filePath = "output.txt";
    |
    | // Open the file for writing
    | std::ofstream outputFile(filePath, std::ios::out);
    |
    | // Check if the file was opened successfully
    | if (!outputFile.is_open()) {
    | throw std::runtime_error("Failed to open the file: " + filePath.string());
    | }
    |
    | // Write "Hello" to the file
    | outputFile << "Hello";
    |
    | // Close the file
    | outputFile.close();
    |
    | std::cout << "File written successfully: " << filePath.string() << std::endl;
    | } catch (const std::exception& e) {
    | std::cerr << "Error: " << e.what() << std::endl;
    | return 1;
    | }
    |
    | return 0;
    |}
    |
    |Here's a breakdown of the code:
    |
    |The program includes the necessary header files: <iostream>
    |for standard input/output, <fstream> for file operations, and
    |<filesystem> for file path management.
    |
    |The main() function is the entry point of the program.
    |
    |The code is wrapped in a try-catch block to handle any
    |exceptions that may occur during the file operations.
    |
    |Inside the try block, the program creates the file path using |std::filesystem::path.
    |
    |An std::ofstream object is created to open the file for
    |writing. The std::ios::out flag is used to indicate that the
    |file should be opened for output.
    |
    |The code checks if the file was opened successfully by
    |checking the is_open() method of the outputFile object. If the
    |file couldn't be opened, an exception is thrown with an error
    |message.
    |
    |The program writes the string "Hello" to the file using the <<
    |operator.
    |
    |The file is then closed using the close() method.
    |
    |If the file was written successfully, a success message is
    |printed to the console.
    |
    |If any exceptions are caught, the error message is printed to
    |the standard error stream (std::cerr), and the program returns
    |a non-zero exit code to indicate an error.
    |
    |This code uses modern C++ features, such as the
    |std::filesystem library for file path management, and robust
    |error handling with exceptions. The program will create the
    |output file in the current working directory, and the file
    |path can be modified as needed.

    . This was what the chatbot answered.

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: Stefan Ram (3:633/280.2@fidonet)
  • From Ben Bacarisse@3:633/280.2 to All on Thu Mar 28 20:27:30 2024
    scott@slp53.sl.home (Scott Lurndal) writes:

    Sam <sam@email-scan.com> writes:
    Stefan Ram writes:

    This (barring typos) is from a book by Bjarne:

    int main()
    {
    string from, to; /* get source and target file names */
    cin >> from >> to;

    ifstream is( from.c_str() ); /* open input stream */
    ofstream os( to.c_str() ); /* open output stream */

    istream_iterator<string> ii(is); /* make input iterator for stream */
    istream_iterator<string> eos; /* input sentinel */
    ostream_iterator<string> oo(os,"\n"); /* make out it. for stream */

    set<string> b(ii, eos); /* b is a set initialized from input */
    copy(b.begin(), b.end(), oo); /* copy buffer to output */ }

    So, is this good style not checking the stream states after opening?

    What's the purpose of the above example? Looks to me like it's demonstrating
    some basic stream operation, so error checking is immaterial. I would think >>that there'll be a separate discussion about error checking where this topic
    would be discussed.

    It's not clear from which book Stefan found this example. It
    doesn't work correctly, however:

    $ cat a.cpp
    #include <string>
    #include <fstream>
    #include <iostream>
    #include <iterator>
    #include <set>

    using namespace std;

    int main()
    {
    string from, to; /* get source and target file names */
    cin >> from >> to;

    ifstream is( from.c_str() ); /* open input stream */
    ofstream os( to.c_str() ); /* open output stream */

    istream_iterator<string> ii(is); /* make input iterator for stream */
    istream_iterator<string> eos; /* input sentinel */
    ostream_iterator<string> oo(os,"\n"); /* make out it. for stream */

    set<string> b(ii, eos); /* b is a set initialized from input */
    copy(b.begin(), b.end(), oo); /* copy buffer to output */
    }

    $ ./a
    i.png
    j.png
    $ ls -l ?.png
    -rw-------. 1 scott scott 2413 Mar 27 13:58 i.png
    -rw-rw-r--. 1 scott scott 2411 Mar 27 15:27 j.png

    The output file is two bytes shorter than the input file.

    How do you know it is not working correctly?.

    The program is not file copy program. SR's first language is not
    English so "copy buffer to output" is understandably not the clearest description. The "copy" is done "through" a set to list the unique
    strings in the input.

    --
    Ben.

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Ralf Fassel@3:633/280.2 to All on Thu Mar 28 20:37:20 2024
    * ram@zedat.fu-berlin.de (Stefan Ram)
    | Now, I have asked a chatbot. Me,

    | |Please show me code in C++ that opens a file and writes
    | |"Hello" to it. The C++ version should be as modern as
    | |possible and the program should have perfect error checking.

    | ; the chatbot,

    | |C++ Code to Write "Hello" to a File
    --<snip-snip>--
    | | // Write "Hello" to the file
    | | outputFile << "Hello";
    | |
    | | // Close the file
    | | outputFile.close();
    | |
    | | std::cout << "File written successfully: " << filePath.string() << std::endl;
    --<snip-snip>--
    | . This was what the chatbot answered.

    As I understand, chatbots 'learn' from examples published on the net.
    Seems like not many examples handle the case that even after successful
    opening of a file the writing to it may still fail.
    Somewhat similar to

    if (exists(file)) {
    assume_open_will_succeed(file);
    ...
    }

    R'

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: ---:- FTN<->UseNet Gate -:--- (3:633/280.2@fidonet)
  • From Sam@3:633/280.2 to All on Thu Mar 28 22:24:13 2024
    Stefan Ram writes:

    Sam <sam@email-scan.com> wrote or quoted:
    What's the purpose of the above example? Looks to me like it's demonstrating >some basic stream operation, so error checking is immaterial. I would think >that there'll be a separate discussion about error checking where this topic >would be discussed.

    It might have been to showcase sets.

    For my C++ tutorial, I want to have "canonical" examples of
    how to read and write files in C++ that can serve as "role
    models" (templates in the general sense) for code.

    I thought I could get the best example code from books by Bjarne.

    Well, without being directly familiar with the book in question: these introductory books tend to focus on individual topics. Such as formatting output and reading input. The details of opening files would be an ancillary subject, at that time.

    But I would expect that prior to that there would be a discussion focused on opening files. An appropriate example, with error checking, will be
    presented and explained at that time.

    But you won't find a "canonical example" of everything, from start to
    finish, in there.

    Now, I have asked a chatbot. Me,

    [ … ]

    . This was what the chatbot answered.

    Bleh.


    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Stefan Ram@3:633/280.2 to All on Thu Mar 28 23:03:22 2024
    Sam <sam@email-scan.com> wrote or quoted:
    Well, without being directly familiar with the book in question: these >introductory books tend to focus on individual topics. Such as formatting >output and reading input. The details of opening files would be an ancillary >subject, at that time.

    |I have never, ever, ever seen a great software developer who
    |does not have amazing attention to detail.
    Rob Walling

    The book was written by Bjarne to be used for teaching programming
    to undergraduates. He complains bitterly that his book is being
    ignored, and instead people are still taught C++ beginning with
    the C parts of the language.

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: Stefan Ram (3:633/280.2@fidonet)
  • From Stefan Ram@3:633/280.2 to All on Thu Mar 28 23:46:27 2024
    ram@zedat.fu-berlin.de (Stefan Ram) wrote or quoted:
    The book was written by Bjarne to be used for teaching programming
    to undergraduates.

    I used this book by searching for an /arbitrary/ use of fstreams.

    Now, I have looked again and found:

    There is a separate chapter dedicated to "Input and Output Streams"
    and a section "I/O error handling". Now, I will look at that chapter
    and section.

    Still, I was/am thinking: If there is a proper way to use I/O streams,
    then it should be visible in /every/ example program.

    This makes me think of an utterance by Matt Bonder:

    |No matter what you want to say, there is one right way to say it,
    |and every other way is wrong. And if you don't already know that
    |one right way, then you're probably going to be wrong.
    Matt Bonder

    . Matt was commenting about his experience learning Japanese.

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: Stefan Ram (3:633/280.2@fidonet)
  • From Stefan Ram@3:633/280.2 to All on Fri Mar 29 00:49:49 2024
    ram@zedat.fu-berlin.de (Stefan Ram) wrote or quoted:
    ifstream is( from.c_str() ); /* open input stream */

    The above from an example program in Bjarnes book.
    In the same book he writes:

    |Don't forget to test a stream after opening it.

    . Yet he did not test "is" after opening it above
    (unless I have missed it).

    Is this a case of "Don't do as I do, but as I say."?

    It could be problematic if prescribed guidelines are
    observed only when the examples appear in the section
    on those guidelines, but not observed in other sections.

    This would be similar to washing your hands while you are in
    a course of the Centers for Disease Control and Prevention,
    but not outside of it.

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: Stefan Ram (3:633/280.2@fidonet)
  • From wij@3:633/280.2 to All on Fri Mar 29 02:02:58 2024
    On Thu, 2024-03-28 at 14:16 +0000, Scott Lurndal wrote:
    ram@zedat.fu-berlin.de=C2=A0(Stefan Ram) writes:
    ram@zedat.fu-berlin.de=C2=A0(Stefan Ram) wrote or quoted:
    The book was written by Bjarne to be used for teaching programming
    to undergraduates.
    =20
    =C2=A0I used this book by searching for an /arbitrary/ use of fstreams.
    =20
    =C2=A0Now, I have looked again and found:
    =20
    =C2=A0There is a separate chapter dedicated to "Input and Output Stream=
    s"
    =C2=A0and a section "I/O error handling". Now, I will look at that chap=
    ter
    =C2=A0and section.
    =20
    =C2=A0Still, I was/am thinking: If there is a proper way to use I/O str=
    eams,
    =C2=A0then it should be visible in /every/ example program.
    =20
    The only proper way to use C++ I/O streams is to _not use them_.
    =20

    Agree. Because normal users of C++ I/O streams don't understand how complex= ity
    is involved. IOW, it only useful because it is compatible with C I/O stream=
    ..
    Or useful for communication in simple case.
    Otherwise, write your own, like mine: https://sourceforge.net/projects/cscall/files/latest/download

    If you are new C++ programer, learn C first.




    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Chris M. Thomasson@3:633/280.2 to All on Fri Mar 29 06:44:29 2024
    On 3/28/2024 7:16 AM, Scott Lurndal wrote:
    ram@zedat.fu-berlin.de (Stefan Ram) writes:
    ram@zedat.fu-berlin.de (Stefan Ram) wrote or quoted:
    The book was written by Bjarne to be used for teaching programming
    to undergraduates.

    I used this book by searching for an /arbitrary/ use of fstreams.

    Now, I have looked again and found:

    There is a separate chapter dedicated to "Input and Output Streams"
    and a section "I/O error handling". Now, I will look at that chapter
    and section.

    Still, I was/am thinking: If there is a proper way to use I/O streams,
    then it should be visible in /every/ example program.

    The only proper way to use C++ I/O streams is to _not use them_.


    Damn right! :^D

    Well, shit happens.

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Bonita Montero@3:633/280.2 to All on Fri Apr 12 23:11:15 2024
    Am 27.03.2024 um 16:11 schrieb Stefan Ram:
    This (barring typos) is from a book by Bjarne:

    int main()
    {
    string from, to; /* get source and target file names */
    cin >> from >> to;

    ifstream is( from.c_str() ); /* open input stream */
    ofstream os( to.c_str() ); /* open output stream */

    istream_iterator<string> ii(is); /* make input iterator for stream */
    istream_iterator<string> eos; /* input sentinel */
    ostream_iterator<string> oo(os,"\n"); /* make out it. for stream */

    set<string> b(ii, eos); /* b is a set initialized from input */
    copy(b.begin(), b.end(), oo); /* copy buffer to output */ }

    So, is this good style not checking the stream states after opening?

    Enable exceptions for failbit and badbit.


    IIRC, out of the box those streams will not throw an exception
    when they cannot open.


    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)