Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Annotating a const member function with pure attribute

Tags:

c++

gcc

The gcc documentation for __attribute__((pure)) states:

Many functions have no effects except the return value and their return value depends only on the parameters and/or global variables. Such a function can be subject to common subexpression elimination and loop optimization just as an arithmetic operator would be. These functions should be declared with the attribute pure.

What does it mean to only depend on the parameters? Consider:

struct Wrapper {
    int i;

    int get() const { return i; }
    void set(int x) { i = x; }
};

Is it valid to label Wrapper::get() as a pure member function? It only depends on the implicit Wrapper instance, but that data could change.

like image 366
Barry Avatar asked Nov 23 '16 16:11

Barry


People also ask

What is const member function explain with the example?

The const member functions are the functions which are declared as constant in the program. The object called by these functions cannot be modified. It is recommended to use const keyword so that accidental changes to object are avoided. A const member function can be called by any type of object.

What is the syntax of a const member function?

Const member functions in C++ To make a member function constant, the keyword “const” is appended to the function prototype and also to the function definition header. Like member functions and member function arguments, the objects of a class can also be declared as const.

What does it mean to mark a function const?

Declaring a member function with the const keyword specifies that the function is a "read-only" function that doesn't modify the object for which it's called. A constant member function can't modify any non-static data members or call any member functions that aren't constant.

What are const member functions option?

A const member function is a member function that guarantees it will not modify the object or call any non-const member functions (as they may modify the object).


1 Answers

Is it valid to label Wrapper::get() as a pure member function? It only depends on the implicit Wrapper instance, but that data could change.

Yes, Wrapper::get() meets the requirements of gcc's pure attribute. Note, however, that __attribute__((pure)) doesn't mean pure in the academic sense, i.e. possessing the property of referential transparency. The latter can be communicated through a stricter __attribute__((const)):

__attribute__((const))

Many functions do not examine any values except their arguments, and have no effects except the return value. Basically this is just slightly more strict class than the pure attribute below, since function is not allowed to read global memory.

Note that a function that has pointer arguments and examines the data pointed to must not be declared const. Likewise, a function that calls a non-const function usually must not be const. It does not make sense for a const function to return void.

But since Wrapper::get() doesn't possess the property of referential transparency implied by __attribute__((const)), it cannot be labeled as such.

EDIT

The guarantee about the pure-ness (in gcc's sense) of a function can be used for optimizing only a block of code that doesn't contain writes to global memory (and, in particular, is not interspersed by calls to non-pure functions). Examples:

struct Wrapper {
    int i;

    int get() const __attribute__((pure)) { return i; }
    void set(int x) { i = x; }
};

long foo(Wrapper* w)
{
    // w->get() can be computed once
    return 2 * w->get() * w->get();
}

long bar(Wrapper* w)
{
    // w->get() can be computed once (even though below code writes to memory,
    // that memory is freshly allocated and cannot be accessed by w->get())
    long result = 2;
    result *= w->get();
    result *= w->get();
    return result;
}

long baz(Wrapper* w)
{
    // both w->get()s must be evaluated, since non-pure code occurs between them
    long result = 2;
    result *= w->get();
    std::cout << "Result after the first muliplication: " << result << std::endl;
    result *= w->get();
    return result;
}
like image 120
Leon Avatar answered Oct 19 '22 00:10

Leon