ぬの部屋(仮)
nu-no-he-ya
  • 1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
         12
    3456789
    10111213141516
    17181920212223
    2425262728  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
       1234
    567891011
    12131415161718
    19202122232425
    26272829   
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28      
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • Unreal Engine 5 でC++からブループリントの自作ノード作成

    前提 Visual C++ の Unreal Engineのインストーラーを導入

    1.C++クラスの追加

    新規C++クラス

    ・[ツール] → [新規 C++ クラス ...] を選択

    ・「親クラスを選択」で 「Blueprint Function Library」を選択し、次へ

    新規 BLUEPRINT FUNCTION LIBRARY に名前を付ける

    [クラスを作成]をクリック。

    ・「プロジェクトにソースが含まれます。エディタを閉じてIDEからビルドしてください。」をOK

    ・「クラス 'MyBlueprintFunctionLibrary' の追加に成功しました。ただしコンテントブラウザに表示されるようにするには'MyProject'モジュールをコンパイルする必要があります。」を「はい」

    Visual Studio とUnreal Engine 5 を一度閉じる。

    VC++が自動で開くが、一度閉じる。

    ※ もう一度slnを開くために、このアイテムのフォルダーを開くからパスを確認しておくと便利。

    さらにUnreal Engineも閉じる。

    2.C++のコード編集

    MyBlueprintFunctionLibrary.h

    上で閉じたslnを手動で開き、MyBlueprintFunctionLibrary.h に以下のメンバ関数宣言を追加する。

    // Fill out your copyright notice in the Description page of Project Settings.
    
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Kismet/BlueprintFunctionLibrary.h"
    #include "MyBlueprintFunctionLibrary.generated.h"
    
    /**
     * 
     */
    UCLASS()
    class MYPROJECT_API UMyBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
    {
    	GENERATED_BODY()
    
        
    	// 追加 
    	UFUNCTION(BlueprintCallable, Category = "MyCategory")
    	static FString MyFirstCppNode();
    
    };
    

    MyBlueprintFunctionLibrary.cpp

    // Fill out your copyright notice in the Description page of Project Settings.
    
    
    #include "MyBlueprintFunctionLibrary.h"
    
    FString UMyBlueprintFunctionLibrary::MyFirstCppNode() {
    
    	return FString("output from C++");
    
    }
    

    プロジェクトをビルド

    普通にビルドする。

    3.Unreal Engineからノードを追加

    閉じたUE5プロジェクトを再び開き、レベルブループリントなどに上記で追加した関数名と同じノードを使用する

    実行

    Unreal Engine 5 画面内にボタンを配置してUIを作る

    ウィジェットブループリントを追加

    ウィジェットを追加しMyUserWidgetと名前を設定

    [追加]→[ユーザーインタフェース]→[ウィジェットブループリント]を選択し、[User Widget]をクリック。名前を「MyUserWidget」へ変更しておく。

    MyUserWidgetをダブルクリックして編集

    [パネル]→[Canvas Panel]を追加する。CanvasPanelを追加しないとボタンが全画面になる。

    次に[一般]→[Button] を追加し、Buttonへ[Text]を追加。ボタンとテキストを親子関係にしてボタンに文字をつける。

    ボタンを押した挙動を設定

    On Clickイベントを追加し、Print textのブループリントを追加しておく。

    UIを画面に表示

    レベルブループリントを開き、

    • Create Widget
    • Promote to Variable
    • Add to Viewport

    を繋げて配置。Create Widgetで最初に追加したMyUserWidgetを設定する。

    テスト

    Rust + windows-rs でMessageBoxAを呼び出す

    MessageBoxAにs!で文字列を渡すと日本語が文字化けするので、encoding_rsでShiftJISへ変換する。さらに0終端にするためにto_vec()でvecへ変換し0をpushする。

    なおencoding_rsを使うための設定をCargo.tomlに加筆する。

    ※ このやり方が正攻法なのかよくわからない。

    main.rs

    use windows::Win32::UI::WindowsAndMessaging::{MessageBoxA, MB_OK};
    use encoding_rs::*;
    
    
    fn main( )->windows::core::Result<()>{
    
      // windows::core::s! マクロ ... 文字列(utf8)をLPCSTR へ変換。
      // MessageBoxWを使う場合はLPCWSTR へ変換するw!を使用。
    
      unsafe {
    
        // windows::core::s!() にそのまま日本語を与えると文字化けする。
        // Rustはu8が基本。 MessageBoxA はnull終端のマルチバイト(ShiftJIS)なので、変換が必要
        let msg = SHIFT_JIS.encode("ハローワールド");
        let ttl = SHIFT_JIS.encode("タイトル");
    
        let mut msg0 = msg.0.to_vec();
        let mut ttl0 = ttl.0.to_vec();
    
        // null 終端にする
        msg0.push(0);
        ttl0.push(0);
    
        let smsg0 = windows::core::PCSTR(msg0.as_ptr());
        let sttl0 = windows::core::PCSTR(ttl0.as_ptr());
        MessageBoxA(
          None,
          smsg0, 
          sttl0,
           MB_OK
        );
      }
    
      Ok(())
    
    }
    

    Cargo.toml

    [package]
    name = "myproject"
    version = "0.1.0"
    edition = "2021"
    # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

    [dependencies.windows]

    version = "0.44.0"
    # 最新版のバージョンは https://github.com/microsoft/windows-rs で確認
    # ・バージョンによってfeaturesを変えなければいけないかもしれない
    # ・バージョンによって何が使えるか(どこにあるか?)が変わる
    #  例えば windows::Win32::Foundation::HINSTANCE やs!は0.32.0にはない
    features = [
        "Win32_Foundation",
        "Win32_UI_WindowsAndMessaging",
    ]

    [dependencies.encoding_rs]
    version="0.8.31"

    TCLAPでC++でコマンドライン引数を解析

    https://github.com/ufz/tclap

    からもダウンロードできる。そこにMIT Licenseと書いてあるのでライセンスはかなり緩い。

    ビルドしなくても使えるのでその点は良いが、インクルードがヘッダファイル一つでも関連ファイルが多いので追加のインクルードディレクトリを指定しなければいけない。

    #include <iostream>
    
    //https://tclap.sourceforge.net/
    
    #include <tclap/CmdLine.h>
    
    int main(int argc, char** argv) {
      int val_int;
      std::string val_string;
    
    
      // Define the command line object
      TCLAP::CmdLine cmd(
        "test program"    // アプリケーションの説明
        , ' '             // コマンドライン引数の区切り文字
        , "0.1"           // ツールのバージョン
        , true            // -hで表示されるヘルプを作成する
      );

      TCLAP::ValueArg<int> arg_i(
          "n"                           // 引数指定方法 -n 123 のように記述
        , "number"                      // 引数指定方法 --number のように記述
        , "count of data"               // ヘルプに表示する説明
        , true                          // 必須項目であることを示す
        , 0                             // 初期値
        , "integer"                     // ヘルプに表示するこのオプションのデータ型
      );
      cmd.add(arg_i);

      TCLAP::ValueArg<std::string> arg_s(
          "t"                           // 引数指定方法 -t abc のように記述
        , "text"                        // 引数指定方法 --text のように記述
        , "text data"                   // ヘルプに表示する説明
        , false                         // 必須項目であることを示す
        , "void"                        // 初期値
        , "text"                     // ヘルプに表示するこのオプションのデータ型
      );
      cmd.add(arg_s);
      // コマンドライン引数を解釈する
      cmd.parse(argc, argv);
    
      // 解釈した値を取得する
      val_int = arg_i.getValue();
      val_string = arg_s.getValue();
    
      // 入力されたオプションを確認
      std::cout << "input : " << val_int << std::endl;
      std::cout << "input : " << val_string << std::endl;
    
      return 0;
    }
    

    実行例1 引数を指定して実行してみる。

    app.exe -n 123
    input : 123
    input : void

    実行例2 ヘルプを作成しているので、-hで使い方表示ができるようになっている。

    app.exe -h
    
    USAGE:
    
       app  [-h] [--version] [-t <text>] -n <integer>
    
    
    Where:
    
       -n <integer>,  --number <integer>
         (required) count of data
    
       -t <text>,  --text <text>
         text data
    
       --,  --ignore_rest
         Ignores the rest of the labeled arguments following this flag.
    
       --version
         Displays version information and exits.
    
       -h,  --help
         Displays usage information and exits.
    
       test program
    
    

    Rust + windows-rs でMessageBoxWを呼び出す

    main.rs

    use windows::Win32::UI::WindowsAndMessaging::{MessageBoxW, MB_OK};
    
    
    fn main( )->windows::core::Result<()>{
    
      // windows::core::s! マクロ ... 文字列(utf8)をLPCSTR へ変換。
      // MessageBoxWを使う場合はLPCWSTR へ変換するw!を使用。
    
      unsafe {
        MessageBoxW(
          None,
          windows::core::w!("ハローワールド"), 
          windows::core::w!("タイトル"),
           MB_OK
        );
    
      }
    
      Ok(())
    
    }
    

    Cargo.toml

    [package]
    name = "myproject"
    version = "0.1.0"
    edition = "2021"
    
    # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
    
    
    [dependencies.windows]
    
    version = "0.44.0"
    
    # 最新版のバージョンは https://github.com/microsoft/windows-rs で確認
    # ・バージョンによってfeaturesを変えなければいけないかもしれない
    # ・バージョンによって何が使えるか(どこにあるか?)が変わる
    #  例えば windows::Win32::Foundation::HINSTANCE やs!は0.32.0にはない
    
    features = [
    #    "alloc",                     # 0.32.0では必要
        "Win32_Foundation",
        "Win32_UI_WindowsAndMessaging",
    ]
    

    Rustでソースコードを二つ以上のファイルに分割する

    1.main.rsの隣にあるファイルを読み込む

    呼び出し側で、

    mod ファイル名

    use ファイル名::関数名

    と書いておけば、呼び出せるようになる。

    あと、構造体や関数が別ファイルに分かれている場合、先頭にpubをつけておかなければいけない。

    同じディレクトリにmain.rsとmyfile.rsがある場合、以下のように記述する。

    main.rs


    // main.rs エントリポイントのあるファイル

    // mod ファイル名
    mod myfile;
    // use ファイル名::関数名(など)
    use myfile::myfunction; // 使いたいものだけ ファイル名::シンボル use myfile::myparam; // use myfile::*; も可能 fn main() { let ab:myparam = myparam{a:1,b:2.0}; myfunction(&ab); }

    myfile.rs


    // myfile.rs 分離したファイル

    // 関数の先頭にpubをつける
    pub fn myfunction(ab : &myparam){ println!("{} {}",ab.a,ab.b); } // 構造体の先頭にpubをつける pub struct myparam{ pub a:i32, // メンバにも pub をつける pub b:f32, }

    https://zenn.dev/newgyu/articles/3b4677b4086768

    2.自分の隣のファイルを読み込む

    main.rs ,  sibling_1st.rs,sibling_2nd.rsがすべて同じ階層にあった場合、main.rsは自分の隣をmodだけで読み込めるが、それ以外は#[path=""]の形でパスを指定しなければならないらしい。

    main.rs

    // main.rs
    
    // mod ファイル名
    mod sibling_1st;
    
    fn main() {
    
        sibling_1st::fnc_1st();
    
    }
    

    sibling_1st.rs

    // sibling_1st.rs
    
    #[path = "./sibling_2nd.rs"]
    mod sibling_2nd;
    
    pub fn fnc_1st(){
    
        sibling_2nd::fnc_2nd();
    
    }
    

    sibling_2nd.rs

    // sibling_2nd.rs
    
    pub fn fnc_2nd(){
    
        println!("my3rd!!!");
    
    }
    

    3.自分の隣のディレクトリ内のファイルを読み込む

    読み込みたいファイルがサブディレクトリにある場合、そのディレクトリ名と同じ名前のrsファイルを置き、中にそれ以下のファイル名をmodで指定する。

    main.rs

    // stc/main.rs
    
    // mod ファイル名
    // 同名のディレクトリを同じ位置に存在させている
    mod mydir;
    
    fn main() {
    
        mydir::sub_1st::fnc_1st();
    
    }
    

    mydir.rs

    // stc/mydir.rs
    
    pub mod sub_1st;
    pub mod sub_2nd;
    

    sub_1st.rs

    // src/mydir/sub_1st.rs
    
    #[path = "./sub_2nd.rs"]
    mod sub_2nd;
    
    pub fn fnc_1st(){
    
        sub_2nd::fnc_2nd();
    
    }
    

    sub_2nd.rs

    // src/mydir/sub_2nd.rs
    
    pub fn fnc_2nd(){
    
        println!("fnc_2nd called");
    
    }
    

    Rust 参照と借用をC++と比較して確認

    参照

    Rust版

    Rustでは、値を変更できる参照は一度に一つしか作れない。

    struct structAB {
      v:i32,
    }
    
    
    fn main() {
    
        let mut oo=structAB{v:5};
    
        let _r:&mut structAB = &mut oo; // OK
        let _g:&mut structAB = &mut oo; // NG 可変の参照。二つ目以降は作れない
        let _b:&mut structAB = &mut oo; // NG 
    
        _r.v=2;
        _g.v=1; // NG そもそも定義できない
        _b.v=0; // NG そもそも定義できない
    
    
    }
    

    immutableな参照であればいくつでも作れる。

    struct structAB {
      v:i32,
    }
    
    
    fn main() {
    
        let mut oo=structAB{v:5};
    
        let _r:&structAB = &oo; // OK
        let _g:&structAB = &oo; // OK &mut でなければいくつでも作れる
        let _b:&structAB = &oo; // OK 
    
        let r = _r.v; // OK 読み取りはできる
        let g = _g.v; // ただし 書き換えられない。
        let b = _b.v; // 
    
    }
    

    C++で類似コード

    Rustの参照は制限がきつく間違った使い方をコンパイラがはじいてくれるweak_ptrと考えるとC++erにとってはわかりやすいかもしれない。

    #include <iostream>
    #include <memory>
    
    struct StructAB {
        int v;
        StructAB(int a) :v(a) {}
    };
    
    int main()
    {
        auto oo = std::make_shared<StructAB>(5);
    
        // C++ では所有権を持たない参照をいくつでも参照を作れる
        std::weak_ptr<StructAB> _r = oo;
        std::weak_ptr<StructAB> _g = oo; // Rustではエラー
        std::weak_ptr<StructAB> _b = oo; // 二つ目以降の可変な参照を作れない
    
        _r.lock()->v = 2;
        _g.lock()->v = 1; // Rustではエラー
        _b.lock()->v = 0; // Rustではエラー
    
    }
    
    

    借用

    借用はC++でいうところのmove。問題は、Rustの場合、(プリミティブ型以外)=代入の挙動がデフォルトでmoveになっていることで、「operator=は常にコピーであることが望ましい」というC++の哲学とは全く相いれない。

    Rust版

    struct structAB {
      v:i32,
    }
    
    fn main() {
    
        let oo=structAB{v:5};
    
        let pp = oo; // ただの=がmoveになる
        
        println!("{} => {}",oo.v , pp.v);// value borrowed here after move  (ooが無効)
    
    }
    

    C++で類似コード

    #include <iostream>
    #include <memory>
    
    struct StructAB {
        int v;
        StructAB(int a) :v(a) {}
    };
    
    int main()
    {
        auto oo = std::make_unique<StructAB>(5);
    
        auto pp = std::move(oo); // ここでmoveすると以降ooはnullptr
    
        printf("%d => %d\n", oo->v,pp->v); // ランタイムエラー (ooがnullptr)
    
    }
    

    それどころか、引数渡しですらデフォルトでmoveなので、迂闊に渡すとライフタイムが切れてしまう。

    Rust版

    struct structAB {
      v:i32,
    }
    
    
    
    fn test(ii:structAB)->i32{
      
      return ii.v*2;
    
      // ii はここで解放される
    }
    fn main() {
    
        let oo=structAB{v:5};
    
        let pp = test(oo); // ここで oo がmoveされてしまうので、test関数から抜けた段階でライフタイムが切れる
    
        println!("{} => {}",oo.v , pp);
    
    }
    

    C++で類似コード

    #include <iostream>
    #include <memory>
    
    struct StructAB {
        int v;
        StructAB(int a) :v(a) {}
    };
    
    
    int test(std::unique_ptr<StructAB> ii) {
        
        return ii->v * 2;
    
        // ii はここでデストラクトされる
    }
    int main()
    {
        auto oo = std::make_unique<StructAB>(5);
    
        auto pp = test(std::move(oo)); // ここでmoveすると以降ooはnullptr
    
        printf("%d => %d\n", oo->v,pp);
    
    }
    

    Rust ライフタイムアノテーションについて

    Rustはライフタイムという概念で参照切れを起こすコードをコンパイルエラーにし、実行時エラーの可能性を最小にしようと努力する(借用チェッカー)。問題は、参照切れを起こす「かもしれない」コードを判定できないので、結果「参照切れを起こすからビルドできない」場合の他に「参照切れを起こすかどうかわからないからビルドできない」という場合も出てくる。

    そんな時に、コンパイラにライフタイムの計算方法を教えてやることで、「わからないからエラー」ではなく「参照切れになるからエラー」と言わせるのがライフタイムアノテーション(らしい)。

    例1 参照切れになるかどうかわからないからエラー

    以下のtest関数の戻り値はgetinput()によって決まる。つまり実行時のユーザの入力次第。

    testは参照を返すので、_r がmain()内の oo を指すのか、 vv を指すのかわからない。

    これを借用チェッカーが評価できないらしく、ライフタイムが計算できないとエラーを出す。

    struct structAB {
      v:i32,
    }
    
    
    
    fn test(jj:&structAB,kk:&structAB )->&structAB{ // error[E0106]: missing lifetime specifier
    
        let val = getinput();// 入力によってどちらが帰るかが決まる
    
        if val%2==0{
            return jj;
        }
        else{
            return kk;
        }
    
    }
    
          
    fn main() {
    
        let oo=structAB{v:5};
    
        let _r;
        {
            let vv=structAB{v:4};
    
            _r = test(&oo,&vv);// _r のライフタイムが oo か vv かわからない
    
        }
    
        println!("result: {}",_r.v);
    }
    
          
          
    fn getinput()->i32{
        let mut buffer = String::new();   
        let ret = std::io::stdin().read_line(&mut buffer);
        let val:i32=buffer.trim().parse().unwrap();
    
        return val;
    
    }
    

    例2 参照切れになる可能性があるからエラー

    上記コードにライフタイムアノテーションを付ける。

    これにより、test関数の各引数は、jj または kk どちらか一方の、より短い方のライフタイムを持つもの、「として借用チェックを行え」という指示となる。

    下の例では、test関数内で入力が偶数であれば呼び出し元の「oo」への参照が帰るので、このプログラムは正常動作するが、ライフタイムが両方ともvvの長さとして計算されるので、_rの参照切れの可能性を検知でき、エラーとできる。

    struct structAB {
      v:i32,
    }
    
    
    // ライフタイムアノテーション('a)付き
    fn test<'a>(jj:&'a structAB,kk:&'a structAB )->&'a structAB{
    
        let val = getinput();
    
        if val%2==0{
            return jj;
        }
        else{
            return kk;
        }
    
    }
    
          
    fn main() {
    
        let oo=structAB{v:5};
    
        let _r;
        {
            let vv=structAB{v:4};
    
            _r = test(&oo,&vv);// 「_rのライフタイムは oo と vv のどちらか短いほう」とみなして検証される
        }
    
        println!("result: {}",_r.v);
    }
    fn getinput()->i32{
        let mut buffer = String::new();   
        let ret = std::io::stdin().read_line(&mut buffer);
        let val:i32=buffer.trim().parse().unwrap();
    
        return val;
    
    }
    

    例3 参照切れにならないコードに変更

    原因が _r の参照切れの可能性なので、参照でなくコピーを保存するようなコードであればエラーでなくなる、ということがわかるので、そのように変更する。

    #[derive(Copy, Clone)]
    struct structAB {
      v:i32,
    }

    // ライフタイムアノテーション('a)付き
    fn
    test<'a>(jj:&'a structAB,kk:&'a structAB )->&'a structAB{ let val = getinput(); if val%2==0{ return jj; } else{ return kk; } }

    fn main() {
    
        let oo=structAB{v:5};
    
        let _r:structAB;
        {
            let vv=structAB{v:4};
    
            _r = test(&oo,&vv).clone();// 参照をしようと思うから破綻するので、コピーすれば問題ない
        }
    
        println!("result: {}",_r.v);
    }

    fn
    getinput()->i32{ let mut buffer = String::new(); let ret = std::io::stdin().read_line(&mut buffer); let val:i32=buffer.trim().parse().unwrap(); return val; }

    なお、Rustでは参照を「借用」(borrow)と言い、所有権すなわち破棄する権利は元の変数にある。

    つまりC++でいうところのweak_ptrに似た性質を持つ。

    Win32API+WinRT+XamlなGUIを.NETやUWPなしで作成する(3)xamlコントロールをxamlテキストから生成

    プログラム冒頭に以下を追加。

    特に今回必要なのはXamlReader。

    // イベントハンドラのため追加
    #include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
    
    
    // XamlReader
    #include <winrt/Windows.UI.Xaml.Markup.h>
    
    
    // イベントハンドラ
    struct handler {
      void ClickHandler(
        winrt::Windows::Foundation::IInspectable const& sender,
        winrt::Windows::UI::Xaml::RoutedEventArgs const& args) {
    
        // クリックされたらメッセージボックス表示
        MessageBox(nullptr, L"Clicked", nullptr, 0);
      }
    };
    

    Windows::UI::Xaml::Markup::XamlReader::XamlReader::Load でテキストからコントロールを作成できる。

    少なくともネイティブWinRTではXamlの中のイベントハンドラ指定はできないらしいので、読み込んでから追加する。

      auto xamltxt = LR"(
    <Page
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
      <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
        <Button x:Name="myButton" Height="116" Width="207">Click Me</Button>
      </StackPanel>
    </Page>
    )";
    
    
      // winrtの文字列形式に変換
      winrt::hstring hs(xamltxt);
      ////////////////////////
      // xamlコントロールを作成
      auto xamlContainer = Windows::UI::Xaml::Markup::XamlReader::XamlReader::Load(hs).as<Windows::UI::Xaml::Controls::Page>();
      desktopSource.Content(xamlContainer);
    
      // ボタンのインスタンスを取り出す
      Windows::UI::Xaml::Controls::Page page = desktopSource.Content().as<Windows::UI::Xaml::Controls::Page>();
      Windows::UI::Xaml::Controls::Button btn = page.FindName(winrt::hstring(L"myButton")).as< Windows::UI::Xaml::Controls::Button>();
    
      // イベントハンドラ追加
      handler hd;
      auto revoker = btn.Click({&hd,&handler::ClickHandler });
    
    
    

    Win32API+WinRT+XamlなGUIを.NETやUWPなしで作成する(2)ボタン追加+イベントハンドラ追加

    ボタンを追加し、クリックしたときのイベントハンドラを追加する。

    include

    // イベントハンドラのため追加
    #include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
    

    イベントハンドラ追加

    // イベントハンドラ
    struct handler {
      void ClickHandler(
        winrt::Windows::Foundation::IInspectable const& sender,
        winrt::Windows::UI::Xaml::RoutedEventArgs const& args) {
    
        // クリックされたらメッセージボックス表示
        MessageBox(nullptr, L"Clicked", nullptr, 0);
      }
    };
    

    ボタン追加

    前回コードのラベルの部分をボタンに変更する。

    ボタン追加は難しくないが、タイトルをwinrt::box_value型で渡さなければいけない。

    イベントハンドラはメンバ関数の場合はthisを渡せばいいが今回はクラス内ではないので構造体のオブジェクトを作成して渡す。

      // ボタンを追加
      Windows::UI::Xaml::Controls::Button btn;
      btn.Content(winrt::box_value(L"Click")); // ボタンタイトル
    
      // イベントハンドラ追加
      handler hd;
      auto revoker = btn.Click({&hd,&handler::ClickHandler });
    
      btn.VerticalAlignment(Windows::UI::Xaml::VerticalAlignment::Center);
      btn.HorizontalAlignment(Windows::UI::Xaml::HorizontalAlignment::Center);
      btn.FontSize(48);
      xamlContainer.Children().Append(btn);
      xamlContainer.UpdateLayout();
      desktopSource.Content(xamlContainer);