Explaining source code

Hi everybody, I'm pretty "new" to C++ but I think I'm starting to get the hang of it. :)

Well I was reading some books about C++ and stumbled accross somethings I simply couldn't get (nor was it explained)..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <fstream>
#include <cstdlib>

using namespace std;

void display(fstream &f)
{
    long x;
    cout << "Here follows the file-content:\n";
    f.seekg(0);
    for ( ; ; )
    {
        f.read((char *)(&x), sizeof(x));
        if (f.eof()) break;
        cout << x << endl;
    }
    f.clear();
}

int main()
{
    long n, i , x, incr;
    fstream f("C:\data", ios::in | ios::out | ios::binary | ios::trunc);
    cout << "Demonstration of editin"
        "from a binary file\n";
    cout << "amount of numbers to write into the file: ";
    cin >> n;
    
    for (i=0; i<n; i++)
    {
        x=10*i;
        f.write((char *)(&x), sizeof(x));
    }
    display(f);
    do
    {
        cout << "type a positive whole number"
            "smaller than "<< n << ": ";
        cin >>i;
    }
    while (i<0 || i>=n);

    f.seekg(i*sizeof(i), ios::beg);
    f.read((char *)(&x), sizeof(x));
    cout << "at that position stands the number: " << x << endl;
    cout << "add xx to that number, xx= ";
    cin >> incr;
    x+=incr;
    f.seekp(i * sizeof(i) ,ios::beg);
    f.write((char *)(&x),sizeof(x));
    display(f);
    system("PAUSE");
    return 0;
}


It ought to explain how "binary file editing and random access" works..

While I can understand the globel flow very easily there are a few things I don't get, mainly: f.read((char *)(&x), sizeof(x));
That first argument: what is that? &x would be a pointer to a long value (wouldn't it?).. But what is that "char *" doing in front of it: I believe I read somewhere you were never allowed to change "pointer types" since then you can easily corrupt the memory?
Similar for the write function: how exactly do they work and what are the arguments?


Also when reading about the stl I came across this snippet:
1
2
typedef set<int, less<int> > settype;
settype S, T;

if I'm correct that woudl just be the same as:
set<int, less<int> > S,T; right? While my book says "to understand less correctly we should explain the subject functieobject, but that's outside the scope of that book" and just stops talking there.... Well I would love to get a very brief explanation: Is this "less" function/class always needed for sets (and maps), and does the thing between <> have to be the same as the first classtype of the set/map?

Thanks in advance,
paul
1)
 
f.read( (char*)(&x), sizeof(x) )


The parameters to the read function are, in order, a pointer to the memory into which to read and the [maximum] number of bytes to read.

Since x is of type long, you are correct in thinking that &x is a pointer to long. Since the read function takes a char* as its first argument, the pointer &x has to be typecasted to the correct type. This is what the (char*) does. It says to the compiler that the expression &x should be considered a char* rather than a long*. sizeof( x ) is a compile-time constant that will evaluate to the number of bytes of memory occupied by x (which is type 'long') and thus is probably 4 or 8, depending upon your CPU/OS.

You are correct in thinking that it is dangerous to change pointer types, but perhaps no more than changing non-pointer types also. The syntax (some-type-here)( expression ) is a C-style cast that is used to defeat C/C++'s typechecking system ostensibly because the programmer "knows better" what the type should be. In good programming, it is best to avoid these kinds of casts for reasons of safety as you mentioned.

2)
You are right. To understand function objects you have to know a little about object-oriented programming. A function object is a class (or struct) that contains a function call operator. Eg:

1
2
3
4
struct is_less_than_four {
    bool operator()( int x ) const 
       { return x < 4; }
};


You can "call" this function like this:

1
2
3
  is_less_than_four  obj;        // Instantiate object
  if( obj( 3 ) )                              // <-- here's how you call it
      cout << "3 is less than 4" << endl;


Note that the syntax for calling it is the same as calling an ordinary function (hence the name function call operator). The use of this is to turn objects into things that can be called like functions. Why is this useful? For generic programming purposes.

So less<int> is one of these function objects. It just happens to be templated. My example above was limited to int; less is not. Hence list<int>() instantiates a less function object for ints.

Set uses this to determine the ordering in which to insert elements into the set. Why is this important? Because it controls the order in which I see the values if I walk from begin() to end(). By default, set uses less<int>, which means that walking from begin() to end() would produce a strictly increasing sequence.

To answer your other questions: set always needs a "function" to compare elements. As I mentioned, the default if you don't specify it is less, and for almost all purposes this should suffice. And no, technically it does not need to be the same, though I can't imagine a scenario in which it is useful to make it different. Given the declaration set< T1, less< T2 > > T1 must be convertible to T2.

Topic archived. No new replies allowed.