Will compiler ignore inline qualifier for my function? - c++

I read that having more than a line in a function will falsify "inline", if so how do i get to know when my function is inlined and vice-versa :/
inline int foo(int x, int y)
{
cout<<"foo-boo";
return (x > y)? x : y;
}

Remember, inlining is only a request to the compiler, not a command. Compiler can ignore the request for inlining. Compiler may not perform inlining in such circumstances like:
If a function contains a loop. (for, while, do-while)
If a function contains static variables.
If a function is recursive.
If a function return type is other than void, and the return statement doesn’t exist in function body.
If a function contains switch or goto statement.

inline is in no way related to the number of lines in a function1. It is just a compiler hint, which the compiler is not, by any means, obliged to follow. Whether a function is really inlined when declared inline, is implementation-defined.
From C++14 standard draft N3690, §7.1.2:
A function declaration (8.3.5, 9.3, 11.3) with an inline specifier
declares an inline function. The inline specifier indicates to the
implementation that inline substitution of the function body at the
point of call is to be preferred to the usual function call mechanism.
An implementation is not required to perform this inline substitution at the point of call [...]
(Formatting mine.)
There are compiler-specific options and attributes to enable/disable inlining for all functions and do other, related stuff. Look up your compiler's documentation for further information.
1 A compiler could take the line count of a function into account when deciding on whether to inline a function or not but that's implementation-defined and not required by the standard.

Related

How to comprehend inline, const and reference in a function declaration?

I noticed a function declaration in my program which included inline, const and reference(&) before the function name. It is easy to follow each of the keywords separately, but can anyone explain the overall meaning when they are used together?
inline const std::string& foo()
{
}
I'm new to CPP programming. Ah, putting so many keywords doesn't make sense to me.
const std::string&
This is the return type of the function, which is a reference to a constant std::string.
inline
This means that this function may be defined multiple times, but you are sure that those definitions are identical and the linker may keep one of those definitions and discard the rest. You usually use this when placing the function definition in a header file, which is included by multiple cpp files, and would have invalidated One Definition Rule otherwise.
Because C++ is very much a free-form language where one could add any number of white-space between operators, keywords and symbols, we could write the function like this instead (with helpful comments):
inline // Hint for the compiler that it's allowed to inline the function
const std::string& // Function return type, a reference to a constant std::string
foo // Function name
() // Function arguments, none
{
// Empty body, not correct since the function is supposed to return something
}
Note that inline is only a hint that the compiler is allowed "inline" the function (basically copy-paste the generated code instead of doing an actual function call). The compiler is allowed to inline function calls anyway, and the inline keyword have some other implications in regards to linkage.

Why does an inline function need pass arguments?

One definition given for an inline function is
If a function is inline, the compiler places a copy of the code of
that function at each point where the function is called at compile
time.
Then my question is: why do we need to pass arguments to an inline function?
E.g
void main()
{
int a = 10;
print(a);
}
inline void print(int a)
{
printf("%d",a);
}
As per the above definition of inline, there should be no compile time errors, as the compiler will translate the code to something like:
void main()
{
int a = 10;
printf("%d",a);
}
Your conclusion is based on an invalid premise. Inline functions are not a macro-like facility that blindly splices the code of the function into the code of the caller. They are a request to the compiler that the function body be inlined if possible, but keeping the normal semantics of the function call/execution. In other words, assuming the code is correct, there should be no observable difference in behavior (other than processor and memory usage, of course) between an inlined and a non-inlined call.
This definition of inline function allows their usage to avoid a number of problems associated with macro, such as clashes of local variables defined in the function with the same name as those in the caller, or calls to function with side effects in the argument (e.g. print(a++) will work correctly with an inline function, but not with a macro).
As a result of this design, the example you provided is a compile-time error.
Inline functions are functions. So they are written and managed like a function.
A compiler may choose to treat these functions differently (may try harder to inline those), but the interface to the user still remains as function.
Moreover it is not guaranteed that inline request would be honored by the compiler.
If you inline a function, it must be defined in each translation unit where it is used and it doesn't give multiple definition link error whether it can be inlined or not by the compiler.
From 7.1.2 Function specifiers [dcl.fct.spec]
A function declaration (8.3.5, 9.3, 11.3) with an inline specifier
declares an inline function. The inline specifier indicates to the
implementation that inline substitution of the function body at the
point of call is to be preferred to the usual function call mechanism.
An implementation is not required to perform this inline substitution
at the point of call; however, even if this inline substitution is
omitted, the other rules for inline functions defined by 7.1.2 shall
still be respected.

What is meant by an attribute of a function?

What this C++11 syntax means?
[[ noreturn ]] void f () {
throw "error";
}
The C++ Standard Working Draft n3797 states,
The first declaration of a function shall specify the noreturn
attribute if any declaration of that function specifies the noreturn
attribute. If a function is declared with the noreturn attribute in
one translation unit and the same function is declared without the
noreturn attribute in another translation unit, the program is
ill-formed; no diagnostic required.
What is meant by an attribute of a function?
A function is defined by its name, its return type, and a list of formal parameters, along with their types. These items constitute the "interface" of the function: they are important to the caller of the function, because they define the way to invoke it.
Attributes, on the other hand, provide a way to tell the compiler additional things about the function that do not alter its interface. When the compiler knows that a function is
An interrupt handler, or
A pure function (i.e. with no side effects or references to state of any kind), or
A function that returns twice (similar to fork), or
A function that never returns, etc.
the compiler can optimize the code better, and provide additional warnings / silence unnecessary warnings.
For example, if you write
main() {
f();
g();
}
and f() is marked noreturn, the compiler will issue a warning about the call of g() being unreachable.
Attributes are a new feature in C++11. Compiler vendors have long offered vendor-specific extensions that allow you to annotate functions in some way or another, but now there is a standard mechanism. There aren't many actual attributes specified by the standard (only noreturn and carries_dependency), but the mechanism for annotating functions is standardized now at least.
That said, the noreturn attribute has non-trivial semantics: If a function declared with this attribute does actually return, the program has undefined behaviour. Compilers should (but don't have to) produce a diagnostic if they can tell that you are returning from a noreturn function. The attribute is valuable to allow optimizations and better diagnostics.
[[noreturn]] attribute is for silence warning.
#include <stdexcept>
[[noreturn]] void report_error()
{
throw std::runtime_error("error");
}
int f(int x)
{
if (x > 0) {
return x;
}
report_error();
}
int main()
{
f(1);
}
If no use [[noreturn]], compiler output warning in f(): warning: control may reach end of non-void function.
From GCC's documentation
"
The noreturn keyword tells the compiler to assume that function cannot return. It can then optimize without regard to what would happen if fatal ever did return. This makes slightly better code. More importantly, it helps avoid spurious warnings of uninitialized variables."

What if I declare a big function as inline function?

I search some related questions (such as Benefits of inline functions in C++?), but I still have questions.
If inline function is just to "provide a simple mechanism for the compiler to apply more OPTIMIZATIONS."
Then can I set every function as inline function?
If I wrongfully set a function as inline function, what would happen concerning performance?
Any threshold that tells me what size of function should not be inline function?
Use inline only to satisfy the One Definition Rule. Don't bother with inline for performance reasons.
If inline function is just to "provide a simple mechanism for the
compiler to apply more OPTIMIZATIONS."
If we're talking about the inline keyword, then this is not what inline is about. Like, at all.
All inline does is ensure that a function doesn't violate the One Definition Rule. It might also provide a hint to the compiler that the compiler should blow the code out inline, which may or may not improve speed, but the compiler is entitled to ignore that hint. And in fact in modern compilers they will ignore this hint a great deal of the time.
One of the cases where the compiler is very likely to not blow the code out inline is with big functions. That doesn't mean the function shouldn't be declared inline, however -- it all depends on how the function is declared, defined and used. But, again, it has nothing to do with performance.
Don't try to outsmart the compiler when it comes to applying optimization techniques. It's far better at making your program fast than you are.
Let's see what the Standard has to say on all of this.
7.1.2 Function specifiers
2/A function declaration (8.3.5, 9.3, 11.3) with an inline specifier
declares an inline function. The inline specifier indicates to the
implementation that inline substitution of the function body at the
point of call is to be preferred to the usual function call mechanism.
An implementation is not required to perform this inline substitution
at the point of call; however, even if this inline substitution is
omitted, the other rules for inline functions defined by 7.1.2 shall
still be respected.
This tells us that inline is a request to the compiler to blow the code out inline, and that compilers are not required to perform that substitution. But this also tells us that regardless of the compiler performing this inline substitution, the "other rules" defined in 7.1.2 still apply.
There was a time, long ago, when the optimization techniques employed by C++ compilers were primitive relative to the compilers of today. Back in those days, it might have made sense to use inline as an optimization technique. But these days, compilers are much better at optimizing your code. The compiler applies techniques that, today, would make your code faster than inlining ever would, even if the function isn't actually inlined. (One possible example, RVO.)
So the end result of this is that while the original intent of 7.1.2/2 might have been to give the programmer a manual-optimization technique, modern compilers optimize so aggressively that this original intent is largely moot.
So all that's left for inline are those "other rules." So what are those other rules? (C++11 verbiage)
4/An inline function shall be defined in every translation unit in
which it is odr-used and shall have exactly the same definition in
every case (3.2). [ Note: A call to the inline function may be
encountered before its definition appears in the translation unit. —
end note ] If the definition of a function appears in a translation
unit before its first declaration as inline, the program is
ill-formed. If a function with external linkage is declared inline in
one translation unit, it shall be declared inline in all translation
units in which it appears; no diagnostic is required. An inline
function with external linkage shall have the same address in all
translation units. A static local variable in an extern inline
function always refers to the same object. A string literal in the
body of an extern inline function is the same object in different
translation units. [ Note: A string literal appearing in a default
argument is not in the body of an inline function merely because the
expression is used in a function call from that inline function. — end
note ] A type defined within the body of an extern inline function is
the same type in every translation unit.
Let's take a look at an example. Suppose we have this class template:
File: foo.h
#ifndef FOO_H
#define FOO_H
#include <string>
#include <sstream>
class StringBuilder
{
public:
template <typename T> inline StringBuilder& operator<<(const T& t)
{
mStream << t;
return * this;
}
operator std::string () const;
private:
std::stringstream mStream;
};
StringBuilder::operator std::string() const
{
return mStream.str();
}
#endif
If we #include this file in main.cpp and use the StringBuilder, everything's fine:
File: main.cpp
#include <iostream>
#include <string>
int main()
{
double d = 3.14;
unsigned a = 42;
std::string s = StringBuilder()
<< "d=" << d << ", a=" << a;
std::cout << s << "\n";
}
Output:
jdibling#hurricane:~/dev/hacks$ ./hacks
d=3.14, a=42
But if we want to use the StringBuilder in a second translation unit, we're going to have a problem:
File: other.cpp
#include <iostream>
#include <string>
#include "foo.h"
void DoSomethingElse()
{
unsigned long l = -12345;
long l2 = 223344;
std::string s = StringBuilder()
<< "l=" << l << ", l2=" << l2;
std::cout << s << "\n";
}
Compiler output:
ninja: Entering directory `.'
[1/3] Building CXX object CMakeFiles/hacks.dir/main.o
[2/3] Building CXX object CMakeFiles/hacks.dir/other.o
[3/3] Linking CXX executable hacks
FAILED: : && /usr/bin/g++ -Wall -std=c++11 -g CMakeFiles/hacks.dir/main.o CMakeFiles/hacks.dir/other.o -o hacks -rdynamic -lboost_regex-mt && :
CMakeFiles/hacks.dir/other.o: In function `std::operator|(std::_Ios_Openmode, std::_Ios_Openmode)':
/home/jdibling/dev/hacks/foo.h:21: multiple definition of `StringBuilder::operator std::string() const'
CMakeFiles/hacks.dir/main.o:/home/jdibling/dev/hacks/foo.h:21: first defined here
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
StringBuilder::operator std::string() is defined twice; once in main.cpp and again in other.cpp -- which violated the One Definition Rule.
We can fix this by making the function inline:
class StringBuilder
{
public:
// [...]
inline operator std::string () const;
// ^^^^^^
private:
std::stringstream mStream;
};
Compiler output:
ninja: Entering directory `.'
[1/3] Building CXX object CMakeFiles/hacks.dir/main.o
[2/3] Building CXX object CMakeFiles/hacks.dir/other.o
[3/3] Linking CXX executable hacks
This works because now operator std::string is defined on both translation units with exactly the same definition. It has the same effect as defining the function directly in the declaraton:
class StringBuilder
{
public:
operator std::string () const
{
return mStream.str();
}
private:
std::stringstream mStream;
};
Just because you make a function inline it doesn't mean the compiler has to make it inline. An inline function is a hint to the compiler, not an order.
A compiler will use a set of metrics, such as optimization level, build type (debug or release), code size etc to determine if a function should be inlined.
The basic programming rule for inlining is the function should be of less then 10 lines;
But there is much more on how compiler sees it and what factors you should consider .
https://en.cppreference.com/w/cpp/language/inline
Then can I set every function as inline function?
If you set a really big function as inline it's fully compiler call if it will consider it as an inlining or not same is true for other small functions.
You should not worry about how the compiler optimizes the code.
Istead the advantages there are some disadvantages or declaring big functions as inline or defining them in .h to consider for inlining . For every inline function compiler tries to fit it into the compiler cache , and if the function is too big and you force inlining then there will be cache miss.
If I wrongfully set a function as inline function, what would happen concerning performance?
It's compiler call if it wants to inline it or not you can force it but,
you have __forceinline in windows to forcefully inline
for that also there is no guarantee that functions will be inlined. You can't force the compiler to inline a particular function, even with the __forceinline keyword. When compiling with /clr, the compiler won't inline a function if there are security attributes applied to the function, but use it judiciously as it fully depend on the judgement of the programmer how you want approach it.
https://learn.microsoft.com/en-us/cpp/cpp/inline-functions-cpp?view=vs-2019
Never force it , if you are not sure .
Any threshold that tells me what size of function should not be inline function?
A function larger then 10 lines a basic rule still there is much to consider.
There is by default inlining happening and compiler optimizes as per the defined rules.
The basic rule you should follow for inlining is to define small function in .h inorder to consider them for inlining . Never put large definations in .h files as they can really become an overhead for compiler .
If we assume that a compiler will paste the inline code at the point where the function is called, you would have large chunks of duplicated code.
Functionally, you may observe a negligible performance improvement, but a large increase in the size of your executable.
The primary reason to have the compiler paste the code rather than call the function is when the code in the function is smaller than or close to the overhead costs in calling the function and returning from it. A rule of thumb is a function of a few statements should be marked as inline. As others have stated, the inline keyword is a hint to the compiler, not a request.
Its ultimately complier decision to make function inline or not so if you declare function as inline its just gives a hint to compiler to make this function inline .

inline function definition in C++?

This a C++ online test question. The test has been done.
class Person
{
std::string name;
public:
std::string const &getname(void) const ;
} ;
inline std::string const &Person::getname() const
{
return name;
}
A: The computer inserts the code of the function getname()
B: The computer generates a call to the function getname()
C: The default parameter values of the calling function are returned
D: All arguments of the function are placed on the memory stack
I choose A. Is it correct ?
Thanks.
The compiler may inline the function.
The compiler/linker will not complain when the function body is found in multiple compilation units, as long as the body is the same.
From the C++11 draft
§ 7.1.2\2
A function declaration (8.3.5, 9.3, 11.3) with an inline specifier
declares an inline function. The inline specifier indicates to the
implementation that inline substitution of the function body at the
point of call is to be preferred to the usual function call mechanism.
An implementation is not required to perform this inline substitution
at the point of call; however, even if this inline substitution is
omitted, the other rules for inline functions defined by 7.1.2 shall
still be respected.
So, as for requirements, it's basically just a normal function, so option B. It might or might not have it's code inserted into the calling function, but that also applies to functions not marked inline, and thus isn't really anything to do with the inline keyword.