tl; dr: আমার মনে হয় আমার স্ট্যাটিক_ভেক্টরটির আচরণের সংজ্ঞা নেই তবে আমি এটি খুঁজে পাচ্ছি না।
এই সমস্যাটি মাইক্রোসফ্ট ভিজ্যুয়াল সি ++ 17 এ I এটি একটি সি ++ 17 প্রোগ্রাম, স্ট্যান্ড :: অ্যালাইনড_স্টোরেজ এবং স্ট্যান্ড :: লন্ডার ব্যবহার করে। আমি এটিকে নীচে সে অংশগুলিতে সিদ্ধ করার চেষ্টা করেছি যা আমি মনে করি এটি সমস্যার সাথে প্রাসঙ্গিক:
template <typename T, size_t NCapacity>
class static_vector
{
public:
typedef typename std::remove_cv<T>::type value_type;
typedef size_t size_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
static_vector() noexcept
: count()
{
}
~static_vector()
{
clear();
}
template <typename TIterator, typename = std::enable_if_t<
is_iterator<TIterator>::value
>>
static_vector(TIterator in_begin, const TIterator in_end)
: count()
{
for (; in_begin != in_end; ++in_begin)
{
push_back(*in_begin);
}
}
static_vector(const static_vector& in_copy)
: count(in_copy.count)
{
for (size_type i = 0; i < count; ++i)
{
new(std::addressof(storage[i])) value_type(in_copy[i]);
}
}
static_vector& operator=(const static_vector& in_copy)
{
// destruct existing contents
clear();
count = in_copy.count;
for (size_type i = 0; i < count; ++i)
{
new(std::addressof(storage[i])) value_type(in_copy[i]);
}
return *this;
}
static_vector(static_vector&& in_move)
: count(in_move.count)
{
for (size_type i = 0; i < count; ++i)
{
new(std::addressof(storage[i])) value_type(move(in_move[i]));
}
in_move.clear();
}
static_vector& operator=(static_vector&& in_move)
{
// destruct existing contents
clear();
count = in_move.count;
for (size_type i = 0; i < count; ++i)
{
new(std::addressof(storage[i])) value_type(move(in_move[i]));
}
in_move.clear();
return *this;
}
constexpr pointer data() noexcept { return std::launder(reinterpret_cast<T*>(std::addressof(storage[0]))); }
constexpr const_pointer data() const noexcept { return std::launder(reinterpret_cast<const T*>(std::addressof(storage[0]))); }
constexpr size_type size() const noexcept { return count; }
static constexpr size_type capacity() { return NCapacity; }
constexpr bool empty() const noexcept { return count == 0; }
constexpr reference operator[](size_type n) { return *std::launder(reinterpret_cast<T*>(std::addressof(storage[n]))); }
constexpr const_reference operator[](size_type n) const { return *std::launder(reinterpret_cast<const T*>(std::addressof(storage[n]))); }
void push_back(const value_type& in_value)
{
if (count >= capacity()) throw std::out_of_range("exceeded capacity of static_vector");
new(std::addressof(storage[count])) value_type(in_value);
count++;
}
void push_back(value_type&& in_moveValue)
{
if (count >= capacity()) throw std::out_of_range("exceeded capacity of static_vector");
new(std::addressof(storage[count])) value_type(move(in_moveValue));
count++;
}
template <typename... Arg>
void emplace_back(Arg&&... in_args)
{
if (count >= capacity()) throw std::out_of_range("exceeded capacity of static_vector");
new(std::addressof(storage[count])) value_type(forward<Arg>(in_args)...);
count++;
}
void pop_back()
{
if (count == 0) throw std::out_of_range("popped empty static_vector");
std::destroy_at(std::addressof((*this)[count - 1]));
count--;
}
void resize(size_type in_newSize)
{
if (in_newSize > capacity()) throw std::out_of_range("exceeded capacity of static_vector");
if (in_newSize < count)
{
for (size_type i = in_newSize; i < count; ++i)
{
std::destroy_at(std::addressof((*this)[i]));
}
count = in_newSize;
}
else if (in_newSize > count)
{
for (size_type i = count; i < in_newSize; ++i)
{
new(std::addressof(storage[i])) value_type();
}
count = in_newSize;
}
}
void clear()
{
resize(0);
}
private:
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage[NCapacity];
size_type count;
};
এটি কিছুক্ষণের জন্য ঠিকঠাক কাজ করার জন্য হাজির। তারপরে, এক পর্যায়ে, আমি এর সাথে খুব সাদৃশ্যপূর্ণ কিছু করছিলাম - আসল কোডটি লম্বা, তবে এটি এর সূত্র ধরে:
struct Foobar
{
uint32_t Member1;
uint16_t Member2;
uint8_t Member3;
uint8_t Member4;
}
void Bazbar(const std::vector<Foobar>& in_source)
{
static_vector<Foobar, 8> valuesOnTheStack { in_source.begin(), in_source.end() };
auto x = std::pair<static_vector<Foobar, 8>, uint64_t> { valuesOnTheStack, 0 };
}
অন্য কথায়, আমরা প্রথমে 8-বাইট ফুবার স্ট্রাক্টগুলি স্ট্যাকের একটি স্ট্যাটিক_ভেক্টারে অনুলিপি করি, তারপরে আমরা প্রথম সদস্য হিসাবে 8-বাইট স্ট্রাক্টের একটি স্ট্যাটিক_ভেক্টরের একটি জোড় তৈরি করি এবং দ্বিতীয় হিসাবে একটি uint64_t করি। আমি যাচাই করতে পারি যে জোড়গুলি তৈরি হওয়ার আগে অবধি স্টেপটিতে সঠিক মান রয়েছে the এবং ... এই জুটিটি নির্মাণের সময় স্ট্যাটিক_ভেক্টরের অনুলিপি নির্মাণকারী (যা কলিং ফাংশনে অন্তর্ভুক্ত করা হয়েছে) এর মধ্যে অপ্টিমাইজেশান সক্ষম হওয়া এই সেগফাল্টগুলি।
দীর্ঘ গল্প সংক্ষিপ্ত, আমি বিচ্ছিন্নতা পরিদর্শন। এটি যেখানে জিনিসগুলি কিছুটা অদ্ভুত হয়; ইনলাইনড কপি কন্সট্রাক্টরের চারপাশে উত্পন্ন উত্সটি নীচে দেখানো হয়েছে - নোট করুন যে এটি আসল কোড থেকে এসেছে, উপরের নমুনাটি নয়, যা বেশ কাছাকাছি তবে জুটির নির্মাণের উপরে আরও কিছু স্টাফ রয়েছে:
00621E45 mov eax,dword ptr [ebp-20h]
00621E48 xor edx,edx
00621E4A mov dword ptr [ebp-70h],eax
00621E4D test eax,eax
00621E4F je <this function>+29Ah (0621E6Ah)
00621E51 mov eax,dword ptr [ecx]
00621E53 mov dword ptr [ebp+edx*8-0B0h],eax
00621E5A mov eax,dword ptr [ecx+4]
00621E5D mov dword ptr [ebp+edx*8-0ACh],eax
00621E64 inc edx
00621E65 cmp edx,dword ptr [ebp-70h]
00621E68 jb <this function>+281h (0621E51h)
ঠিক আছে, সুতরাং প্রথমে আমাদের কাছে দুটি মভ নির্দেশাবলী উত্স থেকে গন্তব্যটিতে গণনা সদস্যকে অনুলিপি করতে হবে; এ পর্যন্ত সব ঠিকই. edx শূন্য হয় কারণ এটি লুপ ভেরিয়েবল। তারপরে আমাদের গণনা শূন্য কিনা একটি দ্রুত চেক আছে; এটি শূন্য নয়, সুতরাং আমরা লুপটির জন্য এগিয়ে যাই যেখানে আমরা 8-বাইট স্ট্রাক্টটি অনুলিপি করতে প্রথমে মেমরি থেকে রেজিস্ট্রেশন করতে দুটি 32-বিট মুভ অপারেশন ব্যবহার করে, তারপরে নিবন্ধ থেকে মেমোরিতে রেকর্ড করি। তবে মজার কিছু আছে - যেখানে আমরা উত্স অবজেক্ট থেকে পড়ার জন্য [ইবিপি + এডেক্স * 8 +] এর মতো কিছু থেকে মুভ আশা করব, তার পরিবর্তে ঠিক আছে ... [ইক্যেক্স]। এটি ঠিক শোনাচ্ছে না। এক্সেক্সের মান কী?
দেখা যাচ্ছে, ইএক্সএক্সে কেবল একটি আবর্জনা ঠিকানা রয়েছে, আমরা সেগফাল্ট করছি ing কোথা থেকে এই মানটি পেল? এখানে তাত্ক্ষণিকভাবে asm এখানে রয়েছে:
00621E1C mov eax,dword ptr [this]
00621E22 push ecx
00621E23 push 0
00621E25 lea ecx,[<unrelated local variable on the stack, not the static_vector>]
00621E2B mov eax,dword ptr [eax]
00621E2D push ecx
00621E2E push dword ptr [eax+4]
00621E31 call dword ptr [<external function>@16 (06AD6A0h)]
এটি দেখতে নিয়মিত পুরানো সিডিসিএল ফাংশন কলের মতো। প্রকৃতপক্ষে, ফাংশনটির ঠিক উপরে উপরে একটি বহিরাগত সি ফাংশনে কল রয়েছে। তবে নোট কী হচ্ছে তা: লক্ষণীয় স্ট্যাকের উপর আর্গুমেন্ট চাপার জন্য ইক্যেক্স অস্থায়ী রেজিস্টার হিসাবে ব্যবহৃত হচ্ছে, ফাংশনটি আহ্বান করা হয়েছে, এবং ... তবে উত্স স্ট্যাটিক_ভেক্টর থেকে পড়ার জন্য নীচে ভ্রান্তভাবে ব্যবহার না করা অবধি ই্যাক্স আবার কখনও স্পর্শ করা হবে না।
অনুশীলনে, বাস্তুতন্ত্রের বিষয়বস্তু এখানে ডাকা ফাংশন দ্বারা ওভাররাইট হয়ে যায়, এটি অবশ্যই করার অনুমতি দেওয়া হয়। তবে তা না পারলেও বাস্তবে এখানে কোনও সঠিক জিনিসটির কোনও ঠিকানা নেই এমন উপায় নেই - সর্বোপরি, এটি স্থানীয় স্ট্যাক সদস্যকে নির্দেশ করবে যা স্থির_ভেক্টর নয়। দেখে মনে হচ্ছে সংকলকটি কিছু বগাস অ্যাসেমব্লি নির্গত করেছে। এই ফাংশনটি কখনই সঠিক আউটপুট উত্পাদন করতে পারে না ।
আমি এখন যেখানে তাই এখন। অদ্ভুত সমাবেশ যখন স্ট্যান্ড :: লন্ডার ল্যান্ডের চারপাশে খেলার সময় অপ্টিমাইজেশন সক্ষম করা হয় তখন অপরিজ্ঞাত আচরণের মতো গন্ধ আমার কাছে আসে। তবে কোথা থেকে আসতে পারে তা আমি দেখতে পাচ্ছি না। পরিপূরক হলেও প্রান্তিকভাবে দরকারী তথ্য হিসাবে, ডান পতাকাগুলির সাথে ঝাঁকুনি এটির সাথে একই জাতীয় সমাবেশ তৈরি করে, যদি না এটি সঠিকভাবে মূল্য পড়ার জন্য এক্সেক্সের পরিবর্তে ebp + edx ব্যবহার করে।
is_iterator
) দয়া করে একটি ন্যূনতম পুনরুত্পাদনযোগ্য উদাহরণ সরবরাহ করুন
clear()
যে সংস্থানগুলিতে ফোন করেছেন সেগুলিতে কেন আপনি কল করছেনstd::move
?