Tracking Down Class Bugs, Explained with Code Examples

UPI Study › Courses › C++ Programming › Free lessons › Lesson 9.7 Free with a free account

Tracking Down Class Bugs

C++ Programming · Chapter 9: Structs, Classes, and File StreamsSection 9.7 · lesson 65 of 84video coming soon

← Designing Clean Interfaces With Abstract TypesNext lesson: Opening Channels to Files →

Earn 3 college credits for C++ ProgrammingRecommended for credit by NCCRS · Computer Science 242 · self-paced · one payment, lifetime access

In this lesson

Frequent mistakes and how to resolve them.

  • Tell which of 3 stages a fault surfaced at
  • Go straight from a message to its cause
  • Diagnose undefined references and const errors
  • Inspect an object's members in a debugger

Transcript

Everything said in the video, section by section (1,469 words). Read along, or search it.

Opening Overview

Three Moments Faults Appear

Faults in classes announce themselves at three different moments, and knowing which moment you're in narrows the search enormously. A missing semicolon fails immediately. A member you declared but never wrote fails later, in a message that names no line at all. And an uninitialized member doesn't fail at all. It produces a plausible wrong answer, sometimes. This lesson is the catalog.

Framework

Three Gates Narrow the Search

Your code passes through three gates. The compiler checks each file on its own. The linker joins the results together. Then the program runs. Each gate produces a different sort of complaint, and the sort tells you where to look, before you've read a word of the message. Compiler messages name a file and a line: a missing semicolon, a missing class prefix, a private member touched, or a const error. Linker messages name a function, but no line: something declared, but never defined. And at run time, there's no message at all: uninitialized members, or a reference to something that's gone. Ask which gate failed first. It rules out two thirds of the list.

Compile Error

The Missing Class Semicolon

Here, nothing is wrong except one line: the class's closing brace has no semicolon. Newer tools say so directly, as shown: expected semicolon after class. Older ones produce a cascade, about an expected initializer before int, and main not being declared. The declaration is treated as running on into whatever follows, so the complaint lands on the next thing in the file. Whenever a run of errors begins right after a class, and none of them mentions the class, check the brace before them. It costs a glance, and is worth checking first, every time.

Link Error

Declared but Never Defined

The compiler is satisfied by a declaration. It knows the function exists, and what it takes. Only when the linker tries to join the call to a body does the absence show up. That's why the message names a function, rather than a line. Here it is, from a build whose Bay file never defines occupy. Other linkers word it as undefined reference, or unresolved external symbol. Either way, there are three causes, checked in this order. The body was never written. Or it was written without the Bay prefix, as an ordinary function. Or the file holding it was never compiled, because the build lists only main dot cpp. So when a message says undefined symbols, or one of its cousins, stop looking for a typo in the calling code. The call is fine. The body is what's absent.

Common Mistake

One Missing Prefix, Two Messages

Forgetting the class name prefix is worth its own look, because one omission produces two different complaints. Here, occupy is defined without Bay in front of it. Without the prefix, it's an ordinary free function that happens to share a name. It has no members, so its first mention of occupied fails at compile time. That's the first message. And separately, the real member function still has no body, so the linker complains too, with the same undefined message as before. Two messages, one cause. Fixing the second without the first sends you round in circles.

Silent Fault

Uninitialized Members Give No Message

Uninitialized members produce no message at any stage. The object exists, the members hold whatever was already in their storage, and the program prints something. It may even be right, which is worse. Here, a bay is created, and asked whether it's free. Reading occupied is undefined behavior: the answer might be 0 or 1, and nobody knows which. So we don't run it. The compiler can't help much. The signature symptoms point here. Different answers on different runs, though nothing in your code changed. A build that works with one setting and fails with another. A count that starts at some large, arbitrary number, because the first increment added one to rubbish. And a flag that's true before anything set it.

The Fix

Giving Every Member a Starting Value

There are two ways to close the gap. Give the member a starting value on the member itself: number starts at 0, and occupied at false. Or set them on creation, in the constructor's initializer list. Either removes the hole permanently, and using both is common. The member's own value covers any path that doesn't set it. The habit worth forming is simply that no data member should be declared without one or the other.

Const Errors

Marking Inspecting Functions Const

Marking a member function const promises it won't change the object. Const objects, including anything received as a const reference, only accept calls to functions carrying that promise. Here, label inspects the bay, but doesn't say so. Is free says so. Show takes a const bay. Calling is free is fine. Calling label fails to build. The message names the promise, not the parameter: the object is const, but the function is not marked const. The instinct is to remove const from the parameter. That makes the message disappear, and throws away a guarantee. The correct fix is the other end. Mark every member function that only inspects the object as const.

Dangling Reference

Never Return a Reference to a Local

A reference is a way of talking about something that lives elsewhere. Returning one is safe only if that something outlives the call. Here, describe returns a reference to a local string. The local stops existing at the closing brace, so the reference refers to nothing at all. It compiles with a warning, shown here, and the behavior is undefined: printing rubbish, appearing to work, or doing different things on different days. Return a string by value when it was computed inside the function. That's always safe. A const reference to a member is fine for reading a large object, while it lives. A plain reference to a member lets outside code change a private member directly, quietly undoing the class's boundary. And a reference to a local: never.

Access Error

Reaching Into Private Members

Touching a private member from outside gives a clear message for once: number is a private member. It points at the exact line, and where it was declared private. There are two honest responses. Either the outside code should be asking the object to do something, rather than reaching into it. Add, or call, a public member function. Or the member genuinely belongs in the public section. Then move it there deliberately. What's never a fix is making everything public to silence the message. The compiler is reporting exactly what the declaration asked it to report.

Debugger Technique

Inspecting Objects Where Messages Fail

For the silent faults, uninitialized members and dangling references, there's no message to read. The tool to reach for is the debugger's view of the object itself. Stop the program at a chosen line, then expand the object in the variables panel, and read its members. One bay shows number 1 and occupied false. Another shows a leftover number nobody assigned. That's the signature of an uninitialized member. Where to stop depends on the question. To check an object is set up correctly, stop just after it's created, and read every member. To see which object a call acts on, stop at the first line of the member function, and expand this. To see when a member changes, stop at each line assigning it. And to check two objects don't share data, stop after a copy, and compare them side by side.

Reference Table

Message Wording and Likely Causes

Here's the table to start from. The wording varies between tools, so the common phrasings are given together. Expected semicolon after class, or an expected initializer just after a class: the brace closing the class. Use of undeclared identifier, or not declared in this scope, in what should be a member function: a missing class name prefix. Is a private member, or private within this context: outside code reaching in. Not marked const, or discards qualifiers: an inspecting function missing const. Undefined symbols, undefined reference, or unresolved external: no body, no prefix, or a file not compiled. Reference to a local returned: something that dies. And no message, with results that vary: uninitialized members. Inspect the object in the debugger.

Quick Check

Which Gate Stops the Lamp

Quick check, with a new class. Check takes a lamp by const reference, and asks whether it's on. Which gate stops this program, and what's the right fix? Pause and predict. The first gate, compiling. Check promises not to change the lamp, but is on never made the same promise. The message says so: function is not marked const. The fix is at the function: mark is on const. Removing const from check's parameter would silence the message, and throw away the guarantee. Built again, it compiles, and prints 0. One word, in the right place, and the guarantee stays.

Key Takeaways

Matching Symptoms to Causes

To summarize. Compile errors name a line. Link errors name a function. Run-time faults name nothing. A cascade of errors right after a class means a missing semicolon. Undefined symbols means no body, no prefix, or a file left out of the build. Not marked const means an inspecting function needs const. And silent, varying results mean uninitialized members, so inspect them in the debugger.

About C++ Programming at UPI Study

C++ Programming (Computer Science 242) is a self-paced online course of 84 video lessons in 11 chapters, from your first program to decisions, loops, arrays, functions, classes, files, pointers and inheritance. It carries a NCCRS credit recommendation for 3 semester credits.

Every lesson transcript is free on pages like this one, and the videos are free with a free UPI Study account. Enrolling adds a practice quiz after each lesson, the graded work and final exam that earn the credit, lifetime access, and an official transcript on completion. UPI Study has helped over 130,000 students with college credits. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.

Why take it here

Why students take C++ Programming with UPI Study

Your first real programming languageC++ teaches how programs really work: variables, control flow, functions, memory and objects. It is the base for data structures, algorithms, systems and game programming, and for most computer-science degrees.
Credit at a fraction of the priceThe same 3 credits can cost $750 or more at a US college. Here it is one payment, self-paced, with lifetime access.
Finish your degree soonerTransfer credits reduce the courses you still owe, so you can graduate earlier or lighten a heavy semester.
Strengthen an applicationA completed college-level course on an official transcript shows admissions and scholarship committees you can do the work.
Study on your own scheduleNo start dates, no deadlines. Watch the lessons, practice, and take the final when you are ready.
130,000+students helped with college creditsACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.

Where the credit goes

Universities that work with NCCRS

C++ Programming carries a NCCRS credit recommendation. These universities work with NCCRS; some are UPI Study's signed partners. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.

Find my college → Not listed? Ask Athena in the corner of this page, or book a 15-minute call.

FAQ

Questions students ask us

About Tracking Down Class Bugs

How can I tell whether a C++ class bug is a compile error, a linker error, or a run-time problem?
Look at what the message names. Compiler errors give a file and a line, such as a missing semicolon, a private member access, or a const error. Linker errors name a function but no line, because something was declared and never defined. Run-time faults, like uninitialized members, produce no message at all. Asking which stage failed first narrows the search.
Why do I get an undefined reference error for a member function I declared in my class?
The compiler accepts a declaration, but the linker needs a body to connect the call to, and none was found. Check three causes in order: the function body was never written, it was written without the class name prefix so it is an ordinary function, or the file containing it was never compiled. The calling code is usually fine.
Why does C++ say the object is const but the function is not marked const, and how do I fix it?
You called a member function on a const object, or a const reference parameter, but that function does not promise to leave the object unchanged. Fix it by marking the inspecting member function const, for example bool isOn() const. Removing const from the parameter silences the error but gives up the guarantee that the function will not modify the object.
How do I find uninitialized member variables in a C++ object when there is no error message?
Use the debugger. Stop the program just after the object is created, then expand it in the variables panel and read every member. A leftover value nobody assigned, such as a strange number, signals an uninitialized member. To prevent it, give each member a starting value where it is declared, in the constructor's initializer list, or both.

About the C++ Programming course

How many college credits is C++ Programming?
C++ Programming (Computer Science 242) carries a NCCRS credit recommendation for 3 semester credits. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.
How much does C++ Programming cost and what is included?
$250, paid once, with lifetime access: all 84 video lessons, a practice quiz after each, the graded work and final exam, and an official transcript when you finish. Students who want several courses choose UPI Study PRO instead.
Which universities accept UPI Study credits?
UPI Study has signed partner agreements with universities such as Thomas Edison State University, University of the People and Charter Oak State College, and works with universities such as Penn State, SNHU and SUNY. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities. Use "Find my college" on this page to check yours.
How long does C++ Programming take?
It is self-paced with no deadlines. The 84 lessons total about 0 hours of video; most students add reading and practice time and finish in a few weeks to a few months, on their own schedule.
How are the exams done?
Quizzes and assignments are online in the course. The final exam is taken online with proctoring; a person on the UPI Study team checks assignments, usually within two days.
How do my credits reach my college?
When the course shows 100% complete, request the official transcript from your dashboard. It is sent to the college you name, and you can send it to more than one. Check your college first with "Find my college" on this page, or ask Athena.

Ready for the full course? Earn 3 credits in C++ Programming.

84 video lessons, a quiz after each one, and the graded work that earns the credit. Recommended for credit by NCCRS.

C++ Programming
3 credits · NCCRS
Enroll →