3

I am currently going through the 5th edition of C++ Primer by Lahoie, Lippman and Moo and have been struggling with a few things.

Firstly, I just wanted to confirm, when using any of the cctype functions, I have to make sure I include the header, right? Because, initially, I forgot to include it and yet it still ran. That's really confused me.

Also, I was browsing for a different problem (which I'll get to) and found another issue haha! When using anything from cctype, are I supposed to write it as std::/write using std::, e.g. if I use the tolower either write std::tolower at every instance/write a using statement for it. This would make sense as it did say that they are "defined in the std namespace" but I didn't realise and have been writing it without and haven't had an issue. And I'm guessing similar for size_t, right?

Speaking of size_t, I have an issue. This is my code:

// Exercise Section 3.5.2., Exercise 3.30

#include <iostream>
#include <cstddef>

using std::cout; using std::endl;

int main()
{
    constexpr size_t num_size = 10;
    int num[num_size] = {};

    for (size_t n = 0; n < num_size; ++n) {
        num[n] = n;
        cout << num[n] << endl;
    }
    return 0;
}

So the code is supposed define an array of 10 ints and give each element the same value as its position in the array.

It runs correctly, but I am receiving an error at the num[n]=n part. It says Implicit conversion loses integer precision: size_t (aka 'unsigned long') to int.

I understand what this means, but my issue is that the book says "when we use a variable to subscript an array, we normally should define that variable to type size_t". I have done this and it gives this error. It does run fine but it seems like that sort of thing that can lead to errors.

P.S. In this code, like I asked above, should I have using std::size_t?

AstroCB
  • 12,337
  • 20
  • 57
  • 73
  • 1
    An individual compiler may pull in certain headers on its own. This doesn't mean you shouldn't "do the right thing" explicitly, as an implementation detail that isn't defined in the standard is subject to change without warning. – DavidO Jul 20 '14 at 22:50
  • Which compiler are you using? – Code-Apprentice Jul 20 '14 at 23:07
  • I wasn't saying that I wasn't going to put it in David. I was just confused. Initially, I forgot to put it in and it ran. Afterwards, I realised and put it in, but wanted to make sure that you were supposed to and I wasn't getting mixed up, that's all. Thanks for the help and I'll bear that in mind! – NintendoMad888 Jul 21 '14 at 23:12
  • Also, thanks Nathan for the advice. Unless I missed it, the book didn't give that. Also, to Code Apprentice, I'm using the most recent version of Xcode. Thanks for the help everyone! – NintendoMad888 Jul 21 '14 at 23:13

5 Answers5

4

Must I include the header even though it works without?

Yes, you must always include at least one header providing each definition / declaration you need, unless the exact prototype / type definition is guaranteed and you put it directly into your source code.

Some standard headers may include others, which might let you get away with being sloppy some of the time, but you will rue it the day you upgrade / port to a different implementation.

I read all the declarations and definitions are "defined in the std namespace" but I didn't realise and have been writing it without and haven't had an issue. And I'm guessing similar for size_t, right?

Yes, it's the same. Due to compatibility, it is possible for the <c...> headers adopted by inclusion from C / Unicode to also provide their symbols in the global namespace.

17.6.1.2 Headers [headers]

1 Each element of the C++ standard library is declared or defined (as appropriate) in a header.175
2 The C++ standard library provides 55 C++ library headers, as shown in Table 14.
3 The facilities of the C standard Library are provided in 26 additional headers, as shown in Table 15.
4 Except as noted in Clauses 18 through 30 and Annex D, the contents of each header cname shall be the same as that of the corresponding header name.h, as specified in the C standard library (1.2) or the C Unicode TR, as appropriate, as if by inclusion. In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std. It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).
5 Names which are defined as macros in C shall be defined as macros in the C++ standard library, even if C grants license for implementation as functions. [ Note: The names defined as macros in C include the following: assert, offsetof, setjmp, va_arg, va_end, and va_start. —end note ]
6 Names that are defined as functions in C shall be defined as functions in the C++ standard library.176
7 Identifiers that are keywords or operators in C++ shall not be defined as macros in C++ standard library headers.177
8 D.5, C standard library headers, describes the effects of using the name.h (C header) form in a C++ program. 178

In my example program I used size_t for the array index. That works, though I get a warning. Should I have done so, and could it in general lead to errors?

Well, naturally the same about namespace std applies, as you guessed.

As to the rest, there's a wonderful phrase: "Good advice comes with a rationale".

The reason you should use std::size_t for indices is that this type a) signals to readers that it's a size or index and b) it is guaranteed to be big enough. In your case, a lowly int, with its guaranteed minimum maximum of 215-1 would have been perfectly fine.
An alternative is just casting to the proper type on assignment.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
2

You declare your array as

int num[num_size] = {};

This means it is an array of int that has 10 elements.

Then you say

for (size_t n = 0; n < num_size; ++n)
    num[n] = n;

Note that n is of type size_t aka unsigned long. Therefore you are putting unsigned long values into your int array, so they are being implicitly converted to int values.

Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • I understood that. I was confused by why the book was telling me to do something that would give me an error, that was my concern. Thanks for the help! – NintendoMad888 Jul 21 '14 at 23:19
  • @NintendoMad888 Well.. it told you to use `size_t` for the type of the thing indexing the array. But you're using the `size_t` thing for two purposes. One in indexing the array (`[n]`), and a second time when assigning to the content of an element of the array (`= n`). The compiler is complaining about the assignment, not the indexing. – Andre Kostur Jul 22 '14 at 00:27
  • I understand that's what it is complaining about. But the problem is, the book has stated to use `size_t` to index an array, and then the exercise question is asking me to give each element the same value as its position. So I use everything I've learnt in order to do what is asked and am given the error. I understand why it is given, I'm just unsure as to why the book is teaching in a way that would give errors. But I guess the book does say "normally" use size_t, so I guess the best thing in this case is to not use it. – NintendoMad888 Jul 22 '14 at 20:39
2

The standard headers put a bunch of stuff in the global namespace. Ideally they wouldn't, but they do. Usually that's because something is really a macro rather than a typedef or function.

You can sometimes get away without including headers because some other header that you have included includes the missing one.

user3553031
  • 5,990
  • 1
  • 20
  • 40
2

You asked:

Firstly, I just wanted to confirm, when using any of the cctype functions, I have to make sure I include the header, right?

Yes, that is right. You might get some function declarations or other declarations indirectly but that is not portable code. You should understand where the standard says a declaration is available and include that header file before using a function, a type, etc.

You asked:

And I'm guessing similar for size_t, right?

Yes, you should use std::size_t.

There is an SO post related to the topic. Browse Difference between size_t and std::size_t.

You asked:

In this code, like I asked above, should I have using std::size_t?

In the loop, it's OK to use int too. The suggestion to use std::size_t for indexing an array is a good suggestion but is not inviolable.

If you choose to use size_t for n, it's OK to use static_cast to convert it to an int to get rid of the compiler warning/error.

num[n] = static_cast<int>(n);
Community
  • 1
  • 1
R Sahu
  • 204,454
  • 14
  • 159
  • 270
2

I have to make sure I include the header, right? Because, initially, I forgot to include it and yet it still ran.

Some standard headers can include other headers. However it is a good idea to include a header explicitly if some declarations from the header are used in the program. It may occur such a way that in other implementations of the included headers the required header will not be included and the compiler will issue an error.

. This would make sense as it did say that they are "defined in the std namespace" but I didn't realise and have been writing it without and haven't had an issue.

The C++ Standard allows compilers to place C standard functions in the global namespace. Though even in this case it is better to specify explicitly namespace std where the function will be declared in any case.

As for the last question then the elements of the array have type int while you assign to them values of type size_t The problem is that type int can not accomodate all values of type size_t and the compiler warns you about this. You could explicitly specify casting that to say the compiler that you know what you are doing.

num[n] = ( int )n;

or

num[n] = static_cast<int>( n );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335