web-dev-qa-db-ja.com

インライン関数-インラインキーワードに対して正確には何ですか?

このリンク では、インライン関数とは何か、インラインキーワードとは何かが説明されています。これらの2つの概念の意味と、実際にどのように使用すべきかを理解したことがないことに気付いたので、読んでいます。私が提供したリンクから引用してコメントしています

インライン関数またはインライン変数(C++ 17以降)は、次のプロパティを持つ関数または変数(C++ 17以降)です。

1)各定義が異なる変換単位で表示される限り、プログラムにはインライン関数または変数の定義が複数存在する場合があります(C++ 17以降)。たとえば、インライン関数またはインライン変数(C++ 17以降)は、複数のソースファイルにインクルードされているヘッダーファイルで定義できます。

ここで私はすでに問題を理解しています、宣言は次のような新しい識別子の仕様です

_void func(void);
_

定義は本体を含む実際の実装ですが

_void func(void) {
  //some code...
}
_

ポイント1)は、異なる変換単位(つまり、ソースファイルごとにヘッダーごとに1つの実装)にある限り、異なる実装を与えることができることを意味しますが、ソースファイルがある場合は困惑します_source.cc_funcの宣言とfuncの別の宣言を持つヘッダーファイルはペア_source.cc+header.h_であり、そのような場合、funcを2回宣言しても意味がありません。

2)インライン関数または変数の定義(C++ 17以降)は、アクセスされる変換ユニットに存在する必要があります(必ずしもアクセスポイントの前にある必要はありません)。

これは、定義を宣言から分離する通常のケースです。最初はヘッダーファイルにあり、2番目はソースファイルにあります。関数を使用する必要がある場合は、ヘッダーのみをインクルードする必要がありますか?アクセスポイントは、リンクフェーズ中にソースによって提供されますよね?

3)外部リンケージ(静的宣言されていないなど)を持つインライン関数または変数(C++ 17以降)には、次の追加プロパティがあります。1)すべての変換ユニットでインライン宣言する必要があります。 2)すべての翻訳単位で同じアドレスを持っています。

これが何を意味するのか簡単な例を教えてください。そのような場合の実際的な事例を想像することはできません。ケース3)は、宣言される関数が静的でない限り、キーワードinlineが必須であると述べています。

私がこれまでに言ったことはすべて正しいですか?

実際には、そのような関数が非常に小さい場合、関数はインラインである必要がありますが、たとえば内部にループがある場合や再帰がある場合など、コンパイラがインラインとして宣言された関数をインライン化するとは限りません(有効なC++はそう述べています)。一般的に、それはコンパイラに依存します、私は今疑問に思います...

2つの関数があるとします。最初の関数は自己完結型であり(内部で他の関数を呼び出すことはありません)、2番目の関数は最初の関数です(引数のために両方とも10行であると想定できます)。それらの両方がインラインで宣言する必要がありますか?それらはヘッダーファイルで宣言する必要がありますか?または、ヘッダーファイルの定義とソースファイルの実装を分離する必要がありますか?何が良いでしょうか?

編集1

関連するアセンブリコード分析を使用して例を使用する場合は、答えの1つに従う方が適切です。

前のコードは無意味だったので削除しました(_-O3_フラグの最適化が設定されていませんでした)。

もう一度始めます... 5つのファイル_header.h_、_src.cc_、_src1.cc_、_src2.cc_、および_main.cc_があります。各翻訳ユニットについて、関連するアセンブリコードが掲載されています。

このようなファイルを3つの異なる方法で操作し、後で生成されたアセンブリコードを観察しました。これは、インラインキーワードがどのように機能するかを理解するのに役立ちました。

例1:

header.h

_#ifndef HEADER_H_
#define HEADER_H_

int func(int a, int b);
int test_1();
int test_2();

#endif /* HEADER_H_ */
_

src.cc

_#include "header.h"

int func(int a, int b)
{
   return a + b;
}
_

src1.cc

_#include "header.h"

int test_1()
{
   int a, b, c;
   a = 3;
   b = 7;
   c = func(a, b);
   return c;
}
_

src2.cc

_#include "header.h"

int test_2()
{
   int a, b, c;
   a = 7;
   b = 8;
   c = func(a, b);
   return c;
}
_

main.cc

_int main(int argc, char** argv)
{
   test_1();
   test_2();
   test_1();
   test_2();
}
_

アセンブリ1:

src.s

_GAS LISTING /tmp/cc0j97WY.s             page 1


   1                    .file   "src.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl _Z4funcii
   6                    .type   _Z4funcii, @function
   7                _Z4funcii:
   8                .LFB2:
   9 0000 8D043E        leal    (%rsi,%rdi), %eax
  10 0003 C3            ret
  11                .LFE2:
  12                    .size   _Z4funcii, .-_Z4funcii
  13                .globl __gxx_personality_v0
  14                    .section    .eh_frame,"a",@progbits
  15                .Lframe1:
  16 0000 1C000000      .long   .LECIE1-.LSCIE1
  17                .LSCIE1:
  18 0004 00000000      .long   0x0
  19 0008 01            .byte   0x1
  20 0009 7A505200      .string "zPR"
  21 000d 01            .uleb128 0x1
  22 000e 78            .sleb128 -8
  23 000f 10            .byte   0x10
  24 0010 06            .uleb128 0x6
  25 0011 03            .byte   0x3
  26 0012 00000000      .long   __gxx_personality_v0
  27 0016 03            .byte   0x3
  28 0017 0C            .byte   0xc
  29 0018 07            .uleb128 0x7
  30 0019 08            .uleb128 0x8
  31 001a 90            .byte   0x90
  32 001b 01            .uleb128 0x1
  33 001c 00000000      .align 8
  34                .LECIE1:
  35                .LSFDE1:
  36 0020 14000000      .long   .LEFDE1-.LASFDE1
  37                .LASFDE1:
  38 0024 24000000      .long   .LASFDE1-.Lframe1
  39 0028 00000000      .long   .LFB2
  40 002c 04000000      .long   .LFE2-.LFB2
  41 0030 00            .uleb128 0x0
  42 0031 00000000      .align 8
  42      000000
  43                .LEFDE1:
  44                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  45                    .section    .note.GNU-stack,"",@progbits
_

src1.s

_GAS LISTING /tmp/cchSilt1.s             page 1


   1                    .file   "src1.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl _Z6test_1v
   6                    .type   _Z6test_1v, @function
   7                _Z6test_1v:
   8                .LFB2:
   9 0000 BE070000      movl    $7, %esi
   9      00
  10 0005 BF030000      movl    $3, %edi
  10      00
  11 000a E9000000      jmp _Z4funcii
  11      00
  12                .LFE2:
  13                    .size   _Z6test_1v, .-_Z6test_1v
  14                .globl __gxx_personality_v0
  15                    .section    .eh_frame,"a",@progbits
  16                .Lframe1:
  17 0000 1C000000      .long   .LECIE1-.LSCIE1
  18                .LSCIE1:
  19 0004 00000000      .long   0x0
  20 0008 01            .byte   0x1
  21 0009 7A505200      .string "zPR"
  22 000d 01            .uleb128 0x1
  23 000e 78            .sleb128 -8
  24 000f 10            .byte   0x10
  25 0010 06            .uleb128 0x6
  26 0011 03            .byte   0x3
  27 0012 00000000      .long   __gxx_personality_v0
  28 0016 03            .byte   0x3
  29 0017 0C            .byte   0xc
  30 0018 07            .uleb128 0x7
  31 0019 08            .uleb128 0x8
  32 001a 90            .byte   0x90
  33 001b 01            .uleb128 0x1
  34 001c 00000000      .align 8
  35                .LECIE1:
  36                .LSFDE1:
  37 0020 14000000      .long   .LEFDE1-.LASFDE1
  38                .LASFDE1:
  39 0024 24000000      .long   .LASFDE1-.Lframe1
  40 0028 00000000      .long   .LFB2
  41 002c 0F000000      .long   .LFE2-.LFB2
  42 0030 00            .uleb128 0x0
  43 0031 00000000      .align 8
  43      000000
  44                .LEFDE1:
  45                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  46                    .section    .note.GNU-stack,"",@progbits
_

src2.s

_GAS LISTING /tmp/cc2JMtt3.s             page 1


   1                    .file   "src2.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl _Z6test_2v
   6                    .type   _Z6test_2v, @function
   7                _Z6test_2v:
   8                .LFB2:
   9 0000 BE080000      movl    $8, %esi
   9      00
  10 0005 BF070000      movl    $7, %edi
  10      00
  11 000a E9000000      jmp _Z4funcii
  11      00
  12                .LFE2:
  13                    .size   _Z6test_2v, .-_Z6test_2v
  14                .globl __gxx_personality_v0
  15                    .section    .eh_frame,"a",@progbits
  16                .Lframe1:
  17 0000 1C000000      .long   .LECIE1-.LSCIE1
  18                .LSCIE1:
  19 0004 00000000      .long   0x0
  20 0008 01            .byte   0x1
  21 0009 7A505200      .string "zPR"
  22 000d 01            .uleb128 0x1
  23 000e 78            .sleb128 -8
  24 000f 10            .byte   0x10
  25 0010 06            .uleb128 0x6
  26 0011 03            .byte   0x3
  27 0012 00000000      .long   __gxx_personality_v0
  28 0016 03            .byte   0x3
  29 0017 0C            .byte   0xc
  30 0018 07            .uleb128 0x7
  31 0019 08            .uleb128 0x8
  32 001a 90            .byte   0x90
  33 001b 01            .uleb128 0x1
  34 001c 00000000      .align 8
  35                .LECIE1:
  36                .LSFDE1:
  37 0020 14000000      .long   .LEFDE1-.LASFDE1
  38                .LASFDE1:
  39 0024 24000000      .long   .LASFDE1-.Lframe1
  40 0028 00000000      .long   .LFB2
  41 002c 0F000000      .long   .LFE2-.LFB2
  42 0030 00            .uleb128 0x0
  43 0031 00000000      .align 8
  43      000000
  44                .LEFDE1:
  45                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  46                    .section    .note.GNU-stack,"",@progbits
_

main.s

_GAS LISTING /tmp/cc5CfYBW.s             page 1


   1                    .file   "main.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl main
   6                    .type   main, @function
   7                main:
   8                .LFB2:
   9 0000 4883EC08      subq    $8, %rsp
  10                .LCFI0:
  11 0004 E8000000      call    _Z6test_1v
  11      00
  12 0009 E8000000      call    _Z6test_2v
  12      00
  13 000e E8000000      call    _Z6test_1v
  13      00
  14                    .p2align 4,,5
  15 0013 E8000000      call    _Z6test_2v
  15      00
  16 0018 31C0          xorl    %eax, %eax
  17 001a 4883C408      addq    $8, %rsp
  18                    .p2align 4,,1
  19 001e C3            ret
  20                .LFE2:
  21                    .size   main, .-main
  22                .globl __gxx_personality_v0
  23                    .section    .eh_frame,"a",@progbits
  24                .Lframe1:
  25 0000 1C000000      .long   .LECIE1-.LSCIE1
  26                .LSCIE1:
  27 0004 00000000      .long   0x0
  28 0008 01            .byte   0x1
  29 0009 7A505200      .string "zPR"
  30 000d 01            .uleb128 0x1
  31 000e 78            .sleb128 -8
  32 000f 10            .byte   0x10
  33 0010 06            .uleb128 0x6
  34 0011 03            .byte   0x3
  35 0012 00000000      .long   __gxx_personality_v0
  36 0016 03            .byte   0x3
  37 0017 0C            .byte   0xc
  38 0018 07            .uleb128 0x7
  39 0019 08            .uleb128 0x8
  40 001a 90            .byte   0x90
  41 001b 01            .uleb128 0x1
  42 001c 00000000      .align 8
  43                .LECIE1:
  44                .LSFDE1:
  45 0020 14000000      .long   .LEFDE1-.LASFDE1
  46                .LASFDE1:
  47 0024 24000000      .long   .LASFDE1-.Lframe1
  48 0028 00000000      .long   .LFB2
  49 002c 1F000000      .long   .LFE2-.LFB2
  50 0030 00            .uleb128 0x0
  51 0031 44            .byte   0x4
  52                    .long   .LCFI0-.LFB2
  53 0032 0E            .byte   0xe
GAS LISTING /tmp/cc5CfYBW.s             page 2


  54 0033 10            .uleb128 0x10
  55 0034 00000000      .align 8
  56                .LEFDE1:
  57                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  58                    .section    .note.GNU-stack,"",@progbits
_

例2:

header.h

_#ifndef HEADER_H_
#define HEADER_H_

inline int func(int a, int b)
{
   return a + b;
}
int test_1();
int test_2();

#endif /* HEADER_H_ */
_

src.cc

_#include "header.h"

/*
int func(int a, int b)
{
   return a + b;
}*/
_

src1.cc

_#include "header.h"

int test_1()
{
   int a, b, c;
   a = 3;
   b = 7;
   c = func(a, b);
   return c;
}
_

src2.cc

_#include "header.h"

int test_2()
{
   int a, b, c;
   a = 7;
   b = 8;
   c = func(a, b);
   return c;
}
_

main.cc

_int main(int argc, char** argv)
{
   test_1();
   test_2();
   test_1();
   test_2();
}
_

アセンブリ2:

src.s

_GAS LISTING /tmp/cczLx8os.s             page 1


   1                    .file   "src.cc"
   2                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
   3                    .section    .note.GNU-stack,"",@progbits
_

src1.s

_GAS LISTING /tmp/ccMFMy9s.s             page 1


   1                    .file   "src1.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl _Z6test_1v
   6                    .type   _Z6test_1v, @function
   7                _Z6test_1v:
   8                .LFB3:
   9 0000 B80A0000      movl    $10, %eax
   9      00
  10 0005 C3            ret
  11                .LFE3:
  12                    .size   _Z6test_1v, .-_Z6test_1v
  13                .globl __gxx_personality_v0
  14                    .section    .eh_frame,"a",@progbits
  15                .Lframe1:
  16 0000 1C000000      .long   .LECIE1-.LSCIE1
  17                .LSCIE1:
  18 0004 00000000      .long   0x0
  19 0008 01            .byte   0x1
  20 0009 7A505200      .string "zPR"
  21 000d 01            .uleb128 0x1
  22 000e 78            .sleb128 -8
  23 000f 10            .byte   0x10
  24 0010 06            .uleb128 0x6
  25 0011 03            .byte   0x3
  26 0012 00000000      .long   __gxx_personality_v0
  27 0016 03            .byte   0x3
  28 0017 0C            .byte   0xc
  29 0018 07            .uleb128 0x7
  30 0019 08            .uleb128 0x8
  31 001a 90            .byte   0x90
  32 001b 01            .uleb128 0x1
  33 001c 00000000      .align 8
  34                .LECIE1:
  35                .LSFDE1:
  36 0020 14000000      .long   .LEFDE1-.LASFDE1
  37                .LASFDE1:
  38 0024 24000000      .long   .LASFDE1-.Lframe1
  39 0028 00000000      .long   .LFB3
  40 002c 06000000      .long   .LFE3-.LFB3
  41 0030 00            .uleb128 0x0
  42 0031 00000000      .align 8
  42      000000
  43                .LEFDE1:
  44                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  45                    .section    .note.GNU-stack,"",@progbits
_

src2.s

_GAS LISTING /tmp/ccNXXmLv.s             page 1


   1                    .file   "src2.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl _Z6test_2v
   6                    .type   _Z6test_2v, @function
   7                _Z6test_2v:
   8                .LFB3:
   9 0000 B80F0000      movl    $15, %eax
   9      00
  10 0005 C3            ret
  11                .LFE3:
  12                    .size   _Z6test_2v, .-_Z6test_2v
  13                .globl __gxx_personality_v0
  14                    .section    .eh_frame,"a",@progbits
  15                .Lframe1:
  16 0000 1C000000      .long   .LECIE1-.LSCIE1
  17                .LSCIE1:
  18 0004 00000000      .long   0x0
  19 0008 01            .byte   0x1
  20 0009 7A505200      .string "zPR"
  21 000d 01            .uleb128 0x1
  22 000e 78            .sleb128 -8
  23 000f 10            .byte   0x10
  24 0010 06            .uleb128 0x6
  25 0011 03            .byte   0x3
  26 0012 00000000      .long   __gxx_personality_v0
  27 0016 03            .byte   0x3
  28 0017 0C            .byte   0xc
  29 0018 07            .uleb128 0x7
  30 0019 08            .uleb128 0x8
  31 001a 90            .byte   0x90
  32 001b 01            .uleb128 0x1
  33 001c 00000000      .align 8
  34                .LECIE1:
  35                .LSFDE1:
  36 0020 14000000      .long   .LEFDE1-.LASFDE1
  37                .LASFDE1:
  38 0024 24000000      .long   .LASFDE1-.Lframe1
  39 0028 00000000      .long   .LFB3
  40 002c 06000000      .long   .LFE3-.LFB3
  41 0030 00            .uleb128 0x0
  42 0031 00000000      .align 8
  42      000000
  43                .LEFDE1:
  44                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  45                    .section    .note.GNU-stack,"",@progbits
_

main.s

_GAS LISTING /tmp/cc2cc5rp.s             page 1


   1                    .file   "main.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl main
   6                    .type   main, @function
   7                main:
   8                .LFB3:
   9 0000 4883EC08      subq    $8, %rsp
  10                .LCFI0:
  11 0004 E8000000      call    _Z6test_1v
  11      00
  12 0009 E8000000      call    _Z6test_2v
  12      00
  13 000e E8000000      call    _Z6test_1v
  13      00
  14                    .p2align 4,,5
  15 0013 E8000000      call    _Z6test_2v
  15      00
  16 0018 31C0          xorl    %eax, %eax
  17 001a 4883C408      addq    $8, %rsp
  18                    .p2align 4,,1
  19 001e C3            ret
  20                .LFE3:
  21                    .size   main, .-main
  22                .globl __gxx_personality_v0
  23                    .section    .eh_frame,"a",@progbits
  24                .Lframe1:
  25 0000 1C000000      .long   .LECIE1-.LSCIE1
  26                .LSCIE1:
  27 0004 00000000      .long   0x0
  28 0008 01            .byte   0x1
  29 0009 7A505200      .string "zPR"
  30 000d 01            .uleb128 0x1
  31 000e 78            .sleb128 -8
  32 000f 10            .byte   0x10
  33 0010 06            .uleb128 0x6
  34 0011 03            .byte   0x3
  35 0012 00000000      .long   __gxx_personality_v0
  36 0016 03            .byte   0x3
  37 0017 0C            .byte   0xc
  38 0018 07            .uleb128 0x7
  39 0019 08            .uleb128 0x8
  40 001a 90            .byte   0x90
  41 001b 01            .uleb128 0x1
  42 001c 00000000      .align 8
  43                .LECIE1:
  44                .LSFDE1:
  45 0020 14000000      .long   .LEFDE1-.LASFDE1
  46                .LASFDE1:
  47 0024 24000000      .long   .LASFDE1-.Lframe1
  48 0028 00000000      .long   .LFB3
  49 002c 1F000000      .long   .LFE3-.LFB3
  50 0030 00            .uleb128 0x0
  51 0031 44            .byte   0x4
  52                    .long   .LCFI0-.LFB3
  53 0032 0E            .byte   0xe
GAS LISTING /tmp/cc2cc5rp.s             page 2


  54 0033 10            .uleb128 0x10
  55 0034 00000000      .align 8
  56                .LEFDE1:
  57                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  58                    .section    .note.GNU-stack,"",@progbits
_

例3:

header.h

_#ifndef HEADER_H_
#define HEADER_H_

inline int func(int a, int b)
{
   return a + b;
}
inline int test_1()
{
   int a, b, c;
   a = 3;
   b = 7;
   c = func(a, b);
   return c;
}
inline int test_2()
{
   int a, b, c;
   a = 7;
   b = 8;
   c = func(a, b);
   return c;
}

#endif /* HEADER_H_ */
_

src.cc

_#include "header.h"

/*
int func(int a, int b)
{
   return a + b;
}*/
_

src1.cc

_#include "header.h"

/*int test_1()
{
   int a, b, c;
   a = 3;
   b = 7;
   c = func(a, b);
   return c;
}*/
_

src2.cc

_#include "header.h"


/*int test_2()
{
   int a, b, c;
   a = 7;
   b = 8;
   c = func(a, b);
   return c;
}*/
_

main.cc

_int main(int argc, char** argv)
{
   test_1();
   test_2();
   test_1();
   test_2();
}
_

アセンブリ3:

src.s

_GAS LISTING /tmp/ccfPkzMC.s             page 1


   1                    .file   "src.cc"
   2                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
   3                    .section    .note.GNU-stack,"",@progbits
_

src1.s

_GAS LISTING /tmp/cckRkoWG.s             page 1


   1                    .file   "src1.cc"
   2                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
   3                    .section    .note.GNU-stack,"",@progbits
_

src2.s

_GAS LISTING /tmp/ccfmb3gI.s             page 1


   1                    .file   "src2.cc"
   2                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
   3                    .section    .note.GNU-stack,"",@progbits
_

main.s

_GAS LISTING /tmp/ccGBsR8z.s             page 1


   1                    .file   "main.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl main
   6                    .type   main, @function
   7                main:
   8                .LFB5:
   9 0000 31C0          xorl    %eax, %eax
  10 0002 C3            ret
  11                .LFE5:
  12                    .size   main, .-main
  13                .globl __gxx_personality_v0
  14                    .section    .eh_frame,"a",@progbits
  15                .Lframe1:
  16 0000 1C000000      .long   .LECIE1-.LSCIE1
  17                .LSCIE1:
  18 0004 00000000      .long   0x0
  19 0008 01            .byte   0x1
  20 0009 7A505200      .string "zPR"
  21 000d 01            .uleb128 0x1
  22 000e 78            .sleb128 -8
  23 000f 10            .byte   0x10
  24 0010 06            .uleb128 0x6
  25 0011 03            .byte   0x3
  26 0012 00000000      .long   __gxx_personality_v0
  27 0016 03            .byte   0x3
  28 0017 0C            .byte   0xc
  29 0018 07            .uleb128 0x7
  30 0019 08            .uleb128 0x8
  31 001a 90            .byte   0x90
  32 001b 01            .uleb128 0x1
  33 001c 00000000      .align 8
  34                .LECIE1:
  35                .LSFDE1:
  36 0020 14000000      .long   .LEFDE1-.LASFDE1
  37                .LASFDE1:
  38 0024 24000000      .long   .LASFDE1-.Lframe1
  39 0028 00000000      .long   .LFB5
  40 002c 03000000      .long   .LFE5-.LFB5
  41 0030 00            .uleb128 0x0
  42 0031 00000000      .align 8
  42      000000
  43                .LEFDE1:
  44                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  45                    .section    .note.GNU-stack,"",@progbits
_

例1と例3は、私が特に興味を持っているものです。インライン関数と非インライン関数の違いを何らかの形で強調する必要があるためです(上記のリンクのポイント1、2、3を参照)。インラインバージョンと比較して、非インライン関数にプロパティの欠如は見られません。誰かが私のために違いを強調することができますか(ここでもポイント1、2、3に関して)?

36
user8469759

たぶん、いくつかの例が役立つでしょう。

1.従来のコンパイル済みライブラリ

foo.h:

_extern int x;
int * f();
_

foo.cpp:

_#include "foo.h"

int x = 25;

int * f() { return &x; }
_

ユーザーには_foo.h_が含まれており、fを呼び出すには、_foo.cpp_を含む翻訳単位にリンクする必要があります。そのような呼び出しはすべて同じアドレスを返します。

2.個別のTUローカル変数

foo.h:

_static int x = 35;
static int * f() { return &x; }
_

_foo.h_を含むすべてのTUは、separateおよびdistinct関数を取得しますf、TUごとに一意の値になる呼び出し。

3.赤ちゃんの最初のODR違反

foo.h:

_static int x = 45;
inline int * f() { return &x; }
_

これはヘッダーのみのライブラリのようですが、_foo.h_が複数のTUに含まれている場合、fは複数回定義されますが、すべての定義ではないため、これはODR違反になります。同一になります。

これはよくある間違いです。回避策には、xをテンプレートにする、またはxint & x() { static int impl = 45; return impl; }などの関数に置き換えるなどがあります。 staticを省略すると、xの定義が複数あるため、リンカーエラーが発生する可能性が高いことに注意してください。 staticは「コードをコンパイルする」ようです。

4.救助のためのC++ 17:適切なヘッダーのみのライブラリ

foo.h:

_inline int x = 55;
inline int * f() { return &x; }
_

このバージョンは機能的に(1)と同等ですが、xおよびfの定義を含む専用の変換ユニットは必要ありません。

42
Kerrek SB

ポイント1)は、異なる翻訳単位にある限り、異なる実装を提供できることを意味します

いいえ、複数の実装が可能であると書かれています。それらが異なる可能性があるとは言っていません。実装はすべて同一である必要があります。

funcの宣言を含むソースファイル_source.cc_と、funcの別の宣言を含むヘッダーファイルがある場合、私は困惑します。翻訳単位はペア_source.cc+header.h_そしてそのような場合に2回funcを宣言しても意味がありません、そうですか?

関数は、インラインであるかどうかに関係なく、必要な数の変換単位で何度でも宣言できます。ここではインラインは要因ではありません。

2)インライン関数または変数(C++ 17以降)の定義は、アクセスされる変換ユニットに存在する必要があります。

これは、定義を宣言から分離する通常のケースです。最初はヘッダーファイルにあり、2番目はソースファイルにあります。関数を使用する必要がある場合は、ヘッダーのみをインクルードする必要がありますか?アクセスポイントは、リンクフェーズ中にソースによって提供されますよね?

いいえ、インライン関数のdefinitionは、リンクフェーズの前に、それを使用するすべてのTU)に存在する必要があります。 allow定義に対するインライン関数の目的です複数のTUで、wantを使用して関数の定義をヘッダーに配置する場合は、inlineを使用します。

ケース3)は、宣言される関数が静的でない限り、キーワードインラインが必須であると述べています。

いいえ、それはまったく言っていません、あなたがそれをそのように解釈することができた方法がわかりません。 inlinestatic関数には内部リンケージがあり、inlinestatic関数には外部リンケージがあり、サブポイント3.1と3.2が適用されるとだけ言っています。 inlineは外部リンケージで機能します。

実際には、そのような関数が非常に小さい場合、関数はインラインである必要がありますが、たとえば内部にループがある場合や再帰がある場合など、コンパイラがインラインとして宣言された関数をインライン化するとは限りません(有効なC++はそう述べています)。一般的に、それはコンパイラに依存します、私は今疑問に思います...

2つの関数があるとします。最初の関数は自己完結型であり(内部で他の関数を呼び出すことはありません)、2番目の関数は最初の関数です(引数のために両方とも10行であると想定できます)。それらの両方がインラインで宣言する必要がありますか?それらはヘッダーファイルで宣言する必要がありますか?または、ヘッダーファイルの定義とソースファイルの実装を分離する必要がありますか?何が良いでしょうか?

オプティマイザーが関数本体のインライン置換を実行するかどうかは、それがinline関数であるかどうかとは強く相関していません。 オプティマイザは、関数がinline関数であるかどうかに関係なく、関数のインライン置換を実行するかどうかを自動的に判断します。関数inlineを宣言します。それらの定義をヘッダーに入れたい。

14
Oktalist

inlineが強制されるかどうかの問題は、とりあえず脇に置いておきましょう(このトピックについてはたくさんの議論があります)。

関数のインライン化は、関数呼び出し(呼び出し)の場所に関数の内容を貼り付けることと同じです。

したがって、次のようになります。

void Hello()
{
  std::cout << "Hello\n";
}

int main()
{
  Hello();
  return 0;
}

Hello関数がインライン化されると、次と同等のものが得られます。

int main()
{
  // Hello();
  std::cout << "Hello\n"; // This is the content of function Hello().
  return 0;
}

コンパイラーは、インライン化としてマークされていない関数をインライン化することができます。この機能は、多くの場合、最適化設定によってトリガーされます。

編集1:インライン化の一般的な理由
関数をインライン化する一般的な理由は、コンテンツが関数を呼び出すオーバーヘッドよりも小さいか等しい場合です。

パラメータをスタックまたはレジスタに移動するなど、関数の呼び出しに関連するプロトコルがあります。プロトコルは、関数のサイズに関係なく存在します。したがって、インライン化すると呼び出し元のプロトコルが削除されます(したがって、プログラムコードのサイズが小さくなり、パフォーマンスが向上します)。

インライン化するもう1つの理由は、関数呼び出しの量を減らすことです。一部のプロセッサでは、分岐命令(関数呼び出し)により、命令キャッシュ(またはパイプライン)が再ロードされます。これには時間がかかります。インライン化により、関数呼び出しが削減され、実行時間が改善されます。

編集2:コード膨張
関数を作成する理由の1つは、コードサイズを小さくすることです。大きな関数をインライン化すると、コードの膨張またはプログラムのサイズが大きくなる可能性があります。

コードの膨張と関数のインライン化は、時間と空間のトレードオフの下にあります。大きな関数のインライン化は実行をスピードアップするかもしれませんが、あなたはそれとスペースを交換しています。共通のコードを関数に配置すると、プログラムのサイズが小さくなる可能性がありますが、実行に時間がかかります。

8
Thomas Matthews