std::atomic_flag의 delete fuction 탐방기
- https://stackoverflow.com/questions/27314485/use-of-deleted-function-error-with-stdatomic-int
“Use of deleted function” error with std::atomic_int
I want to use an std::atomic_int variable. In my code, I have: #include
책 따라서 예제 코드를 쓰고 돌려보고있었다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Spinlock
{
public:
Spinlock();
~Spinlock();
void lock();
private:
std::atomic_flag flag
public:
void unlock();
};
Spinlock::Spinlock() : flag(ATOMIC_FLAG_INIT)//c2280 error
{
;
}
Spinlock::~Spinlock()
{
}
void Spinlock::lock()
{
while (flag.test_and_set());
}
void Spinlock::unlock()
{
flag.clear();
}
여기서 delete function 에러가 떴다.
아니 왜 예제 코드를 그대로 하는데 에러가 뜨냐고
찾아보다가 결국
라이브러리를 뜯어보게되었다.
해당 컴파일러는 msvc 14.2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// STRUCT atomic_flag
#define ATOMIC_FLAG_INIT \
{}
struct atomic_flag { // flag with test-and-set semantics
bool test_and_set(const memory_order _Order = memory_order_seq_cst) noexcept {
return _Storage.exchange(true, _Order) != 0;
}
bool test_and_set(const memory_order _Order = memory_order_seq_cst) volatile noexcept {
return _Storage.exchange(true, _Order) != 0;
}
void clear(const memory_order _Order = memory_order_seq_cst) noexcept {
_Storage.store(false, _Order);
}
void clear(const memory_order _Order = memory_order_seq_cst) volatile noexcept {
_Storage.store(false, _Order);
}
#ifdef __clang__ // TRANSITION, VSO#406237
constexpr atomic_flag() noexcept = default;
#else // ^^^ no workaround / workaround vvv
atomic_flag() noexcept = default;
#endif // TRANSITION, VSO#406237
#if 1 // TRANSITION, ABI
atomic<long> _Storage;
#else // ^^^ don't break ABI / break ABI vvv
atomic<bool> _Storage;
#endif // TRANSITION, ABI
};
매크로로 정의된 ATOMIC_FLAG_INIT 이건 그냥 {} 였고
atomic_flag는 atomic을 변수로 가지는 구조체였다.
따라서
1
atomic_flag flag({});
에서 계속 에러가 뜨고있었던것.
atomic쪽 삭제된 함수를 불러서 문제가 발생하는것.
1
2
3
atomic_flag() noexcept = default;
atomic(const atomic&) = delete;
뇌피셜의 추론에 의하면 {} 이 아마 암시적으로 atomic으로 형변환이 되어서 atomic 복사생성자를 부르는것같다.
표준이 뒤에 바뀐것도 아닌데 일단 예제 코드는 틀렸고
해결책은 이니셜라이즈는 비워두고
초기화에 아무런 손을 대지않고 default를 부르게하거나
ATOMIC_FLAG_INIT을 억지로 쓰려면 이렇게 하는게 정답이었다.
1
2
3
4
5
6
7
8
9
10
11
class Spinlock
{
public:
Spinlock();
~Spinlock();
void lock();
private:
std::atomic_flag flag = ATOMIC_FLAG_INIT;
public:
void unlock();
};
고전적인 C형식의 스트럭트 대입이 답이었다.
아무래도 코드에 거부감이 좀 있다.
스트럭트, 클래스는 말그대로 형식인데 static도아닌데 여기에 값을 대입을 해놓는다니.
처음에는 이거 옛날 C++표준에선 적용이 안되는건데.라고 생각을했지만 atomic자체가 C++11에서부터
지원을 해주는것이기에 상관이 없었던거다.
이니셜라이저에서는 대입연산을 못쓰기때문에 ATOMIC_FLAG_INIT는 아무짝에도 쓸모없고 atomic을
쓰려고했더니 에러만 불러서 애먹인 놈이 되었다.
근데 딱히 문제가 있다는 내용을 못 봤는데 왜 나만 이런문제가 생긴걸까?