質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

UE4

UE4はUnreal Engine(アンリアルエンジン)の第4世代です。 UEは、Epic Gamesより開発されたゲームエンジンです。

Q&A

解決済

1回答

3070閲覧

「ハンドルされない例外が 0x00007FFFA161478C で発生しました : Microsoft C++ の例外: char。」のエラー回避を行う方法

roatt

総合スコア45

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

UE4

UE4はUnreal Engine(アンリアルエンジン)の第4世代です。 UEは、Epic Gamesより開発されたゲームエンジンです。

0グッド

0クリップ

投稿2022/02/23 11:44

編集2022/02/23 11:47

前提・実現したいこと

前提として、以下画像のようにcsvデータから特定の列の名前を参照してその列の1つ下以降の数値をUE4のBlueprintFunctionLibraryから生成されたVisual Studioのcppファイル内のvector<string>に格納しその中で値を使用できるようにしたいです。
例)”値R”を参照し、vector<string> a = {0.4,0.4,0.47,0.404}というように値を格納

↓csvSeach_test.csv
イメージ説明

そのためにまずVisualStudioにて下記URLと同じように列番号と行番号を参照して、セルの値を表示ができる確認を行いたいです。
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11116705496?__ysp=Qysr44GnY3N244GL44KJ6aCF55uu5qSc57Si

発生している問題・エラーメッセージ

デバッグすると、以下「該当のソースコード」の「 throw "指定された列が見つかりませんでした"; //指定された列が見つからないときは例外を投げる」でエラーが発生しました。(「該当のソースコード」の★部分)

ハンドルされない例外が 0x00007FFFA161478C で発生しました (csvSearch_test.exe 内): Microsoft C++ の例外: char (メモリの場所 0x00000067B1CFF618)。

該当のソースコード

cpp

1#include <iostream> 2#include <fstream> 3#include <map> 4#include <sstream> 5#include <string> 6#include <vector> 7 8using std::cout; using std::endl; 9using std::ifstream; using std::string; 10using std::getline; using std::istringstream; 11 12/** 13*csvファイルの先頭行から指定された列名の列番号を取得 14*@param fin 15*@param col_name 列名 16*/ 17int get_col(ifstream& fin, string col_name) { 18 string line; //csvの行の文字列 19 getline(fin, line); //先頭行を読み込む 20 string token; //分割したセルの値を格納する変数 21 int col = 0; //処理中の列の列番号 22 istringstream stream(line); //行の文字列をカンマで分割 23 24 while (getline(stream, token, ',')) { 25 if (token == col_name) { 26 return col; //現在の列番号を返す 27 } 28 ++col; 29 } 30 throw "指定された列が見つかりませんでした"; //指定された列が見つからないときは例外を投げる ★ 31} 32 33/** 34*csvファイルから指定された行の文字列を取得する 35*@param fin 36*@param col_row 行番号 37*@return csvファイルの指定された行の文字列 38*/ 39string get_row(ifstream& fin, int row) { 40 int cur_row = 1; //読み込んだ行数。先頭行は読み込み済みだから「1」を初期値に指定 41 string line; //ファイルの行を格納する変数 42 43 while (getline(fin, line)) { //ファイルを1行ずつ読み込む 44 if (cur_row == row) { //指定された行が見つかった 45 return line; //行の文字列を返す 46 } 47 ++cur_row; 48 } 49 throw "指定された行が見つかりませんでした"; //指定された行が見つからないときは例外を投げる 50} 51 52/** 53*csvファイルの行の文字列から指定された列のセルの値を取得する 54*@param line csvファイルの行の文字列 55*@param col 列番号 56*@return csvセルの値 57*/ 58string get_cell(string line, int col) { 59 string token; //分割したセルの値を格納する変数 60 int cur_col = 0; //処理中の列の列番号 61 istringstream stream(line); //行の文字列をカンマで分割 62 63 while (getline(stream, token, ',')) { 64 if (cur_col == col) { //指定されたセルが見つかった 65 return token; //セルの値を返す 66 } 67 ++cur_col; //次のセルへ 68 } 69 throw "指定されたセルが見つかりませんでした"; //指定されたセルが見つからないときは例外を投げる 70} 71 72/** 73*csvファイルから指定したセルの値を取得する 74*@param filename csvファイルのファイル名 75*@param row 行番号 76*@aram col_name 列名 77*/ 78string get_data(string filename, int row, string col_name) { 79 ifstream fin(filename); //ファイルを開く 80 int col = get_col(fin, col_name); //列名に該当する列の列番号を取得 81 string line = get_row(fin, row); //csvファイルの指定された行の文字列を取得 82 return get_cell(line, col); //行の文字列からセルの値を取得 83} 84 85int main() 86{ 87 //try { 88 cout << get_data("C:/csvSeach_test.csv", 1, "日付") << endl; 89 //} 90 //catch (std::out_of_range& exception) { 91 // throw; 92 //} 93 94}

試したこと

調べると例外処理がうまくいっていないということがわかり、throwのあとに例外クラスを入れなければならないというところまではわかりました。
なので、int main内にtry catchを入れ、関数内にthrowの後に「std::out_of_range」や「std::range_error」、「std::runtime_error」を入れてみましたが、それでもエラーになってしまいました。
エラーコードの「c++の例外:」のあとに「std::out_of_range」や「std::range_error」、「std::runtime_error」出てしまい、うまくエラー回避ができない状態です。

補足情報(FW/ツールのバージョンなど)

UE4 ver.4.27.2
VisualStudio 2022

C++も独学で組んでいる初心者のため、お手数ではありますが、丁寧なご説明までいただけましたら大変ありがたいです。
ご不明点等ございましたらご質問頂ければ幸いです。
お手数ですが、よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

C++初心者とのことですが、C++は強い型付けの言語に属するので、すべてのデータについて型を意識することが大事です。
「throw なんとか」をしたとき、それをcatchする際はその「なんとか」が何の型であるかを意識する必要があります。なぜなら、throwされた変数の型とcatchする際の変数の型が一致していなければ、例外はcatchされないからです。

catch(std::out_of_range& ex) なら、catchできるのはstd::out_of_range型です。

C++

1try 2{ 3 std::out_of_range exception_object("error message"); 4 throw exception_object; 5} 6catch(std::out_of_range& ex) 7{ 8}

上記は、throwしている変数exception_objectがstd::out_of_range型なので、catchする際もstd::out_of_range型で指定します。

intの例

C++

1try 2{ 3 throw 0; 4} 5catch(int i) 6{ 7}

リテラル0は、int型です。

さて、throw "なんかメッセージ"と書いた場合、"なんかメッセージ"の型はなんでしょうか?
これはC++初心者には地味に難しい問題なのですが、catchする際はchar const*でcatchできます。

C++

1try 2{ 3 throw "abc"; 4} 5catch(char const* message) 6{ 7}

このあたりはC++でもかなり基本的な部分に属する知識です。全体的な知識を「独習C++」などで一度きちんと学習しておいたほうが、結果的には作りたいものを早く作れると思いますよ。

投稿2022/02/23 12:02

編集2022/02/23 12:05
ttact

総合スコア170

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

roatt

2022/02/23 13:00 編集

早々のご回答ありがとうございます! なるほど、例外処理にもそれに合ったデータ型があるのですね。 throwが使われている関数内にご教示いただいたtry catch文を入れたら、現在今回発生しているエラーは発生しなくなりました。 本当にありがとうございました。
ttact

2022/02/23 22:06

発展的な内容なので回答には記載しませんでしたが、近年は例外はあまり使われなくなってきている傾向があるように思います。最近流行ってきたGoやRustにはtry-catch形式の例外機構はないですし。 C++の場合は、(Cの時代と同じように)関数の戻り値でエラーを返すように組むようになってきました。ただしその場合、エラーが無視されないよう戻り値に[[nodiscard]]属性というのを付けます。以下をご参照ください。 https://cpprefjp.github.io/lang/cpp17/nodiscard.html
roatt

2022/02/24 06:08

ありがとうございます。 ご紹介いただいたURLを参考にコードを追加しました。 また、こちらも初歩的な質問になってしまうかと思いますが、catchに入った場合throw”コメント”のコメント部分はデバッグのステップインを行うと処理内容として見ることができるという理解でよいのでしょうか?
ttact

2022/02/24 06:36

> catchに入った場合throw”コメント”のコメント部分はデバッグのステップインを行うと処理内容として見ることができるという理解でよいのでしょうか? 「処理内容として見る」というのが具体的に何を指しているのかがよくわかりませんが、「catch節({}の内側)にステップインしたりブレークポイントを張ったりして、throw時に投げた例外データをデバッガ(のウォッチ等)で参照できるかどうか」というご質問であれば、それは参照できます。 「throw "abc";」というコードを見ると、あたかも例外をthrowするときに"abc"というデータを生成しているように想像されるかもしれませんが、そうではありません。C/C++は"abc"のような定数文字列データについては、ひとまとめにしてmain()関数実行前にメモリ上に展開しています。このとき"abc"自体は4バイトのデータですが、その格納領域にはメモリアドレスが割り当てられています。「throw "abc";」では単にその格納領域の先頭アドレスがthrowされるだけです。64bit OSで、例えばその"abc"が次のように格納されているとします: ADDR | Value 0x12345678ABCDEF00 | 0x61(asciiコードで'a') 0x12345678ABCDEF01 | 0x62 0x12345678ABCDEF02 | 0x63 0x12345678ABCDEF03 | 0x00 このとき「throw "abc";」は、"abc"格納領域の先頭アドレスである0x12345678ABCDEF00をchar const*型でthrowします。catch(char const* message)におけるmessageには、このアドレス値0x12345678ABCDEF00が格納されます。デバッガのウォッチでmessageを参照したり、printf()でmessageを%sで出力したりすれば、messageが指している領域にある文字列が読めるでしょう。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問