Tôi đã làm việc trên một con trỏ chia sẻ (được gọi là Xử lý) thực hiện cho công cụ trò chơi của dự án sinh viên của tôi, và chúng tôi chạy vào một lỗi mà chúng tôi không thể giải thích. Đối với một số lý do, tại một thời điểm nhất định trong nhà máy của chúng tôi, có một con trỏ bên trong không hợp lệ được chuyển đến một nhà máy thông qua một tay cầm, điều này gây ra sự cố trong quá trình tải nguyên mẫu của chúng tôi. Chúng tôi đã gỡ lỗi thông qua quy trình này hàng giờ và đã phá vỡ bất kỳ câu lệnh phức tạp nào xuống các phiên bản đơn giản nhất để gỡ lỗi dễ dàng hơn. Cuối cùng tôi đã phân lập được vấn đề xuống trình tạo bản sao của lớp Xử lý. Tuy nhiên, nó vẫn có vẻ như có một số bước trung gian nơi con trỏ bên trong được giải phóng. Tôi đọc tất cả các bài viết tôi có thể tìm thấy về những gì có thể gây ra vấn đề này, và không tìm thấy bất cứ điều gì. Cuối cùng, tôi quyết định xem xét việc tháo gỡ và xem liệu tôi có thể tìm ra điều gì đang xảy ra không. Đây là hàm tạo bản sao mà không cần tháo gỡ.x86/C++ - Con trỏ tới con trỏ: Const bị vi phạm bởi trình biên dịch?
template <class TYPE>
Handle<TYPE>::Handle(const Handle<TYPE>& rhs, bool weak) : m_weak(weak), m_ref_count(rhs.m_ref_count), m_ptr(rhs.m_ptr)
{
if(!m_weak)
++(*m_ref_count);
}
Đây là trình tạo bản sao có tháo gỡ.
template <class TYPE>
Handle<TYPE>::Handle(const Handle<TYPE>& rhs, bool weak) : m_weak(weak), m_ref_count(rhs.m_ref_count), m_ptr(rhs.m_ptr)
{
013FFF50 push ebp
013FFF51 mov ebp,esp
013FFF53 sub esp,0CCh
013FFF59 push ebx
013FFF5A push esi
013FFF5B push edi
013FFF5C push ecx
013FFF5D lea edi,[ebp-0CCh]
013FFF63 mov ecx,33h
013FFF68 mov eax,0CCCCCCCCh
013FFF6D rep stos dword ptr es:[edi]
013FFF6F pop ecx
013FFF70 mov dword ptr [this],ecx
013FFF73 mov eax,dword ptr [this]
013FFF76 mov cl,byte ptr [weak]
013FFF79 mov byte ptr [eax],cl
013FFF7B mov eax,dword ptr [this]
013FFF7E mov ecx,dword ptr [rhs]
013FFF81 mov edx,dword ptr [ecx+4]
013FFF84 mov dword ptr [eax+4],edx
013FFF87 mov eax,dword ptr [this]
013FFF8A mov ecx,dword ptr [rhs]
013FFF8D mov edx,dword ptr [ecx+8]
013FFF90 mov dword ptr [eax+8],edx
if(!m_weak)
013FFF93 mov eax,dword ptr [this]
013FFF96 movzx ecx,byte ptr [eax]
013FFF99 test ecx,ecx
013FFF9B jne Handle<Component>::Handle<Component>+60h (013FFFB0h)
++(*m_ref_count);
013FFF9D mov eax,dword ptr [this]
013FFFA0 mov ecx,dword ptr [eax+4]
013FFFA3 mov edx,dword ptr [ecx]
013FFFA5 add edx,1
013FFFA8 mov eax,dword ptr [this]
013FFFAB mov ecx,dword ptr [eax+4]
013FFFAE mov dword ptr [ecx],edx
}
Vấn đề (như xa như tôi có thể nói) là ở đây:
013FFF6D rep stos dword ptr es:[edi]
Như mọi người đều biết, điều này được sử dụng để xóa bộ nhớ một cách nhanh chóng. Tuy nhiên, hướng dẫn này là xóa con trỏ mà con trỏ trỏ đến con trỏ trỏ đến, và không chỉ vậy, mà nó còn vi phạm const, như được truyền trong Handle là tham chiếu const. Tôi không chắc đó có phải là vấn đề VS hay không, một số loại cờ được thiết lập trong cài đặt xây dựng của chúng tôi khiến nó xảy ra, nhưng trình tạo bản sao hoạt động tốt cho đến khi chúng tôi cố tạo các nguyên mẫu với nó.
Bất kỳ trợ giúp nào sẽ được đánh giá rất nhiều!
EDIT 1: Tôi đã nghiên cứu thêm vấn đề sau khi một số nhận xét đưa ra ánh sáng mà tôi có thể trả về một biến tạm thời ở đâu đó trong mã của tôi. Tôi đã không thể tìm thấy bất cứ điều gì có thể đề nghị tôi đã làm như vậy, nhưng tôi đã sàng lọc thông qua một số tháo gỡ nhiều hơn để xem nếu tôi có thể tìm thấy bất kỳ gợi ý. Đây là chức năng CreateGenericArchetype của chúng tôi, đó là nơi mà vấn đề được cắt xén.
Handle<Object> ObjectFactory::CreateGenericArchetype(const std::wstring &ArchetypeName)
{
/* Create The Object */
auto archetype = mComponentFactoryMap.find(std::wstring(L"Object"));
Handle<Component> created_component = archetype->second->CreateArchetypeComponent();
Handle<Object> retVal = static_handle_cast<Object>(created_component);
retVal->mArchetypeName = ArchetypeName;
mArchetypeMap.insert(std::pair<std::wstring, Handle<Object>>(ArchetypeName, retVal));
return Handle<Object>(retVal, true);
}
Dòng đó là gây ra tất cả các vấn đề của chúng tôi (tại thời điểm này) là thế này:
Handle<Component> created_component = archetype->second->CreateArchetypeComponent();
Đương nhiên, tôi mở rộng gỡ lỗi của tôi để CreateArchetypeComponent là tốt, vì vậy đây là quá:
Handle<Component> ComponentTypeFactory<Object>::CreateArchetypeComponent() const
{
Object* created_object = new Object;
Component* casted_object = static_cast<Component*>(created_object);
Handle<Component> newComponent(casted_object);
newComponent->mType = mType;
newComponent->mID = GetNewID();
return newComponent;
}
Object được thừa hưởng từ Component, vì vậy yếu hèn static_cast của Object để Component là hợp lệ, và các nhà xây dựng xây dựng thành công Handle từ Component *. Vấn đề nảy sinh khi chúng ta cố gắng trả về Handle mà chúng ta đã xây dựng bên trong hàm.Đây là tháo gỡ của sự tương tác rằng:
return newComponent;
005602AD push 0
005602AF lea eax,[newComponent]
005602B2 push eax
005602B3 mov ecx,dword ptr [ebp+8]
005602B6 call Handle<Component>::Handle<Component> (04EA050h)
005602BB mov ecx,dword ptr [ebp-110h]
005602C1 or ecx,1
005602C4 mov dword ptr [ebp-110h],ecx
005602CA mov byte ptr [ebp-4],0
005602CE lea ecx,[newComponent]
005602D1 call Handle<Component>::~Handle<Component> (04F2E7Bh)
005602D6 mov eax,dword ptr [ebp+8]
}
00EB02D9 push edx
00EB02DA mov ecx,ebp
00EB02DC push eax
00EB02DD lea edx,ds:[0EB0318h]
00EB02E3 call @[email protected] (0E4BA9Eh)
00EB02E8 pop eax
00EB02E9 pop edx
00EB02EA mov ecx,dword ptr [ebp-0Ch]
00EB02ED mov dword ptr fs:[0],ecx
00EB02F4 pop ecx
00EB02F5 pop edi
00EB02F6 pop esi
00EB02F7 pop ebx
00EB02F8 mov ecx,dword ptr [ebp-10h]
00EB02FB xor ecx,ebp
00EB02FD call @[email protected] (0E4E9BAh)
00EB0302 add esp,130h
00EB0308 cmp ebp,esp
00EB030A call __RTC_CheckEsp (0E41C3Dh)
00EB030F mov esp,ebp
00EB0311 pop ebp
00EB0312 ret 4
******* trở lại CreateGenericArchetype *******
005C2639 call __RTC_CheckEsp (04F1C3Dh)
005C263E mov dword ptr [ebp-1D4h],eax
005C2644 mov ecx,dword ptr [ebp-1D4h]
005C264A mov dword ptr [ebp-1D8h],ecx
005C2650 mov byte ptr [ebp-4],4
005C2654 mov edx,dword ptr [ebp-1D8h]
005C265A push edx
005C265B lea ecx,[created_component]
005C265E call Handle<Component>::Handle<Component> (04EA050h)
******* constructor sao chép tháo từ ở trên đây *******
005C2663 mov byte ptr [ebp-4],6
005C2667 lea ecx,[ebp-174h]
005C266D call Handle<Component>::~Handle<Component> (04F2E7Bh)
Handle<Object> retVal = static_handle_cast<Object>(created_component);
Trừ khi nhà xây dựng bản sao của tôi được gọi với "created_component" như xử lý rhs được coi là trả về biến cục bộ, tôi không thể thấy nó có thể xảy ra ở đâu , u nless đó là bởi vì các xử lý trả về từ CreateArchetypeComponent là trên stack khi nó được truyền cho constructor sao chép và sau đó được xóa.
Có vẻ như lệnh 'rep' chỉ xóa hết ngăn xếp và không chạm vào đối tượng. –
Được bình chọn cho đối tượng hiếm hoi đó: một câu hỏi tốt, được nghiên cứu kỹ lưỡng! –
BTW, việc xóa con trỏ 'const' không vi phạm' const'. Bạn có thể làm tốt 'const int * const p = new int [42]; delete [] p; 'Và nếu bạn có một con trỏ trỏ tới một cá thể' const', thì con trỏ đầu tiên là 'const', nhưng không phải là dữ liệu trỏ tới (trong trường hợp này là con trỏ thứ hai), vì vậy bạn có thể" rõ ràng "con trỏ thứ hai. – vsoftco