Main Content

Expensive-to-Read Objects in Bug Finder

Polyspace® Bug Finder™ reports several defects when your code performs an expensive read operation that can instead be replaced by a more efficient read operation. When evaluating the efficiency of a read operation, Polyspace considers the costs of reading an object by copy and by dereferencing. An object can be more expensive to read by copy than by dereferencing, and vice versa. This topic clarifies when Bug Finder considers a copy operation to be expensive and when Bug Finder considers a dereferencing operation to be expensive.

Objects That Are Expensive to Read by Copy

During a read operation, Polyspace considers an object to be expensive to read by copy compared to dereferencing if either of these conditions are true:

  • The object is not a trivially copy-constructible type. A trivially copy-constructible type has a trivial copy constructor and a trivial destructor. To find out if the type of your object is trivially copy-constructible, use the C++ type trait std::is_trivially_copy_constructible.

  • The object is trivially copy-constructible but its size is greater than twice the size of a void* pointer:

    sizeof(object) > 2 × sizeof(void*)

Examples of objects that are expensive to read by copy include std::string objects, user-defined classes that are not trivially copy-constructible, most sequence containers such as std::vector, all associative containers such as std::map, and all unordered associative containers such as std::unordered_map.

Consider this code:

#include <vector>

extern void foo(std::vector<int> v);
extern void bar(const std::vector<int> &v);

void by_value(const std::vector<int> &v)
{
	foo(v);
}

void by_ref(const std::vector<int> &v)
{
	bar(v);
}

 Instructions for by_value()

 Instructions for by_ref()

Both by_value() and by_ref() pass an std::vector object to a function. A copy of the vector is passed by to foo() while a reference to the vector is passed to bar(). Vector objects are not trivially copyable and their sizes are larger than 2 × sizeof(void*). In a typical toolchain, the passing the vector by value takes 18 instructions, including five call instructions. Passing the vector by reference takes five instructions with only one call instruction. Polyspace considers vector objects expensive-to-read by copy.

Objects That Are Expensive to Read by Dereference

During a read operation, Polyspace considers an object to be expensive to read by dereference compared to copying if both of these conditions are true:

  • The object has a trivially copy-constructible type.

  • The size of the object is less than or equal to 2 × sizeof(void*)

Typical examples of objects that are expensive to read by dereference include plain integral types of various sizes. For example, consider this code:

#include <cstddef>

size_t double_by_ref(size_t const &r)
{
	return 2 * r;
}
size_t double_by_value(size_t const r)
{
	return 2 * r;
}

 Instructions for double_by_ref()

 Instructions for double_by_value()

The function double_by_ref() accepts a size_t object by reference while the function double_by_value() accepts a size_t object by value. Objects of type size_t are trivially-copyable and have size less than or equal to 2 × sizeof(void*). In a typical toolchain, the function double_by_ref() takes at least one more instruction than the function double_by_value(). Polyspace considers integral types expensive-to-read by dereference.

See Also

External Websites