3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

生やしたバグ集

Last updated at Posted at 2021-08-10

ただの頭回ってなかったとか注意不足みたいなやつじゃなくて、知らないと沼るやつを集めた
やらかす度に追加されていきます
言語は、特に書いていなければCかC++です。

(Python / numpy) 参照は複雑怪奇

Pythonでは代入でオブジェクトがコピーされないという罠があるのは有名である。
では以下の例はどうだろう ?

a = [[1, 2], [3, 4]]
b = a[0]
a[0] = a[1]
print(b)

これはさすがに[1, 2]が出力される。しかし

import numpy as np
a = np.array([[1, 2], [3, 4]])
b = a[0]
a[0] = a[1]
print(b)

では[3 4]が出力される。やってられない

string に int を代入

std::string s;
s = 3;

コンパイルは通る。s は "3" にはならない。
この代入、使われているのはoperator= (char c);で、charをstringに代入してその1文字からなる文字列にする。
つまりこの場合文字コード3の文字1文字からなる文字列になる (は~~~ ?)

整数リテラルそのまま書くとさすがに気づくかもしれないけど変数を代入しようとしてstd::to_string忘れたとかだと起こりそうでしょう ?

グローバル変数の初期化順序

a.hpp
struct TestStruct {
  TestClass ();
};
a.cpp
std::vector<TestStruct *> instances;
TestStruct::TestStruct () {
  instances.push_back(this);
}
b.cpp
TestStruct hoge;

色々突っ込み所のあるコードだが、一番致命的なのはプログラムが開始しても instances が空かもしれないということだ。
異なるファイル間でのグローバル変数の初期化順序は未規定(だよね ?) なので instanceshoge より後に初期化されると... ?
そもそもその場合初期化されてないstd::vectorを使うのは大丈夫なのか ? というのはよく分からん。

符号なし整数

int index = -3;
auto element = array[(index % array.size() + array.size()) % array.size()];

めっちゃ書きそう。壊れる。(細かいことは忘れたが%で型を共通にするときにサイズの大小と符号の有無によって何に合わせるかが決まって、このコードは多くの場合符号なし側に合わせちゃう)

reverse_iterator.base()

a.rbegin().base() は、std::prev(a.end()) ではなく a.end() (え~)
確かに「じゃあ a.rend().base() はどうなるんや」って言われたらその通りなんだけど...なんか設計もやる

std::ifstreamのbinary指定

バイナリファイルをstd::ifstreamで開くときはstd::ios::binaryを指定する必要あり。
デフォルトのままだとテキストモードで開かれてバイナリファイルの中の\r\nが全部\nになるし0x1Aに出会おうものならそこで読み込みが打ち切られます。

constexprな変数を参照してはいけない(?)

以下のコードをGCC 12.1.0, -std=c++11 でコンパイルすると undefined reference to 'TestStruct::INF' でリンカーエラーになります。
よく分からないが発生条件シビアなせいでサンプルコード書くのにも時間がかかった

#include <vector>

struct TestStruct {
	static constexpr int INF = 1000000000;
	std::vector<int> a;
	
	TestStruct (int n) {
		a.assign(n, INF);
	}
};

int main() {
	TestStruct tmp(100);
	return 0;
}

decltypeの結果にキャストするときは参照に注意

事の発端はジェネリックラムダ式

#include <iostream>
#include <vector>
#include <cstdint>

typedef uint32_t u32;
typedef uint64_t u64;

int main() {
	auto f = [] (const auto &a, auto &b) {
		b.resize(a.size());
		for (size_t i = 0; i < a.size(); i++) b[i] = (decltype(b[0])) a[i] * a[i];
	};
	std::vector<u32> a{1, 2, 3};
	std::vector<u64> b;
	f(a, b);
	for (auto i : b) std::cerr << i << std::endl;
	return 0;
}

decltype(b[0])u64になってほしいけどu64 &になってます。
a[i]u32 &なのでコンパイルが通らないと思いきや、なんとu32 &u64 &に変換されて-Wall -Wextra -Wpedantic下ですら警告なしでぶっ壊れます。strict aliasing rule違反で、実際にはa[i]a[i + 1]をu64として読むようなコードが生成されてるものと思われます。
ジェネリックラムダ式でなく普通に(u64 &) a[0]とか書くと警告してくれるのにどうして...
std::remove_referenceをしましょう

libcurlはCのライブラリです

#include <curl/curl.h>

int main() {
  CURL *curl;
  std::string url = "https://example.com";
  // ...
  curl_easy_setopt(curl, CURLOPT_URL, url);
  // ...
  return 0;
}

CURLOPT_URL を指定した時の curl_easy_setopt は第3引数に const char * を期待するんですって
コンパイル通るんかい💢
こんなん絶対何回でもやらかすに決まってるのでラッパー書いて二度とlibcurl生で触らなくていいようにするわ

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?