배열을 만들려고하지만 개체의 기본 초기화가없는 다음 코드가 있습니다. 새로운 일이 생길 것 같은데 완벽하게 전달하고 싶습니다만, 객체의 소멸자가 emplace 함수 내부에서 호출된다는 것을 알았습니다. 다음배치 새롭고 완벽한 전달
start emplace
0 constructed
0 move constructed
0 destructed
end emplace
start emplace
1 constructed
1 move constructed
1 destructed
end emplace
1
start emplace
2 constructed
2 move constructed
2 destructed
end emplace
0 destructed
1 destructed
2 destructed
그것은 객체가 일단 설치하다 함수 내부 (분명 UB 임) 한때 구성된 회 소멸되는 것을 나타내고, 다음과 같이
#include <iostream>
#include <memory> // std::uninitialized_copy, std::allocator...
#include <utility> // std::move...
#include <bitset>
struct Int {
int i;
Int () : i (-1) { std::cout << "default constructed\n"; }
Int (const int i_) : i (i_) { std::cout << i << " constructed\n"; }
Int (Int && int_) : i (std::move (int_.i)) { std::cout << i << " move constructed\n"; }
Int (const Int & int_) : i (int_.i) { std::cout << i << " copy constructed\n"; }
~Int () { std::cout << i << " destructed\n"; i = -1; }
};
template <typename T, size_t S = 64>
class NoInitArray {
std::bitset<S> m_used;
T *m_array = reinterpret_cast < T* > (::operator new (sizeof (T) * S));
public:
T const &operator [ ] (const size_t idx_) const {
return m_array [ idx_ ];
}
NoInitArray () { }
~NoInitArray () {
for (size_t idx = 0; idx < S; ++idx) {
if (m_used [ idx ]) {
reinterpret_cast< const T* > (m_array + idx)->~T ();
}
}
}
template<typename ...Args>
void emplace (const size_t idx_, Args &&... value_) {
std::cout << "start emplace\n";
m_used [ idx_ ] = 1;
new (m_array + idx_) T (std::forward<T> (value_) ...);
std::cout << "end emplace\n";
}
};
int main () {
NoInitArray<Int> nia;
nia.emplace (0, 0);
nia.emplace (1, 1);
std::cout << nia [ 1 ].i << std::endl;
nia.emplace (2, 2);
return 0;
}
이 프로그램을 실행 한 결과는 한 번 NoInitArray의 파괴에.
질문은 "왜 내 Int 객체의 소멸자가 emplace 함수 내부에서 호출 되었습니까?"라는 질문이 있습니다.
컴파일러, 최신 Clang/LLVM on Windhoze.
EDIT1 : Int 구조체에 이동 및 복사 생성자를 추가했습니다. 이제 계산이 일치합니다 (예 : 2 개의 구성 및 2 개의 삭제).
EDIT2 : 배치 변경 새 라인을 new (m_array + idx_) T (std::forward<T> (value_) ...);
에서 new (m_array + idx_) T (value_ ...);
으로 이동 생성자가 필요없이 불필요한 생성/제거 작업을 방지합니다.
EDIT3 : 향후 독자를위한 것입니다. 위와 같이, ~ NoInitArray()는 메모리를 누설합니다. m_array에서 delete를 호출하는 것은 나쁜 소식이며 m_array [0]의 소멸자 (Clang/LLVM에서 호출)입니다 (하지만 지금까지 이해 한대로 보장 할 수는 없습니다, 즉 UB). std :: malloc/std :: free는 갈 길인 것처럼 보이지만 일부는 그렇게하면 모든 지옥이 붕괴되고 다리가 빠질 수 있다고 말합니다.
는 복사 생성자 호출을 계산해야합니다 임시 값 T.를 작성합니다. –
@BenVoigt 복사 생성자가 일반 생성자를 호출하지 않습니까? 이것이 문제가되면 전송이 의도 한대로 작동하지 않는다는 것을 의미합니다. 어떻게하면이 작업을 수행 할 수 있습니까? 즉, 복사하는 대신 오브젝트를 이동할 수 있습니까? – degski
아니요, 복사 생성이 기본 생성자에 연결되지 않습니다. 이동이 아니라 복사가 예상되는 경우 이동 및 복사 생성자의 사용자 정의 버전을 제공하고 각각에 고유 한 메시지를 기록하십시오. –