Expanding the Image API

Benefits of the [[nodiscard]] Attribute

What's the benefit of using the nodiscard attribute for our getter functions?

Abstract art representing computer programming

The [[nodiscard]] attribute is a powerful feature in C++ that can help prevent subtle bugs and improve code clarity. Let's explore why it's beneficial, especially for getter functions in our Image class.

Purpose of [[nodiscard]]

The [[nodiscard]] attribute tells the compiler to issue a warning if the return value of a function is ignored. This is particularly useful for functions where discarding the return value is likely to be a mistake.

Why Use It for Getters?

Getter functions are designed to return information, and it's rarely intentional to call them without using their return value. By marking getters as [[nodiscard]], we can catch potential mistakes where a developer might accidentally ignore the returned value.

Let's look at an example using our Image class:

class Image {
 public:
  [[nodiscard]]
  int GetWidth() const {
    return mImageSurface->w;
  }

  [[nodiscard]]
  int GetHeight() const {
    return mImageSurface->h;
  }

  [[nodiscard]]
  ScalingMode GetScalingMode() const {
    return mScalingMode;
  }

  void SetDimensions(int Width, int Height) {
    // Implementation...
  }
};

int main() {
  Image MyImage{"example.png"};

  MyImage.GetWidth();  

  // This is fine
  int Width = MyImage.GetWidth(); 

  // Also fine
  MyImage.SetDimensions(
    MyImage.GetWidth(), MyImage.GetHeight()
  );
}
warning: ignoring return value of function declared with 'nodiscard' attribute

In this example, the compiler will warn us about the line where we call GetWidth() without using its return value. This could indicate a logical error in our code.

Preventing Logical Errors

Consider a scenario where we want to check if an image's dimensions have changed:

bool HasImageChanged(
  const Image& OldImage, const Image& NewImage
) {
  OldImage.GetWidth();   
  OldImage.GetHeight();  
  NewImage.GetWidth();   
  NewImage.GetHeight();  

  return true;  // Always returns true!
}

Without [[nodiscard]], this function would compile without warnings, even though it's not actually comparing anything. With [[nodiscard]], we get warnings that help us catch this mistake:

warning: ignoring return value of function declared with 'nodiscard' attribute
warning: ignoring return value of function declared with 'nodiscard' attribute
warning: ignoring return value of function declared with 'nodiscard' attribute
warning: ignoring return value of function declared with 'nodiscard' attribute

Improved Code Clarity

Using [[nodiscard]] also serves as a form of self-documentation. It clearly communicates to other developers (or your future self) that the return value of this function is important and should be used.

When Not to Use [[nodiscard]]

While [[nodiscard]] is great for getters, it's not appropriate for all functions. For example, a function like Render() in our Image class might not need [[nodiscard]] because it's normal to call it for its side effects without caring about a return value.

In conclusion, using [[nodiscard]] for getter functions in our Image class helps catch potential bugs, improves code clarity, and communicates intent to other developers. It's a simple addition that can significantly enhance the robustness of our code.

Answers to questions are automatically generated and may not have been reviewed.

sdl2-promo.jpg
Part of the course:

Game Dev with SDL2

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, unlimited access

This course includes:

  • 51 Lessons
  • 100+ Code Samples
  • 91% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved