Tôi tự hỏi, nếu có bất kỳ nhà kinh doanh nào trong C++ có thể làm sáng tỏ tình huống kỳ lạ này. Một trong những ví dụ đi kèm với động cơ vật lý Box2D đang gặp sự cố với thông điệp "phương pháp ảo thuần túy được gọi", nhưng chỉ với một trình biên dịch nhất định (và chỉ trong bản phát hành bản phát hành).constructor nội tuyến lặp lại trong khung ngăn xếp gây ra "phương pháp ảo thuần túy được gọi là"?
Box2D như bạn có thể biết là một đoạn mã khá vững chắc vì vậy tôi nghĩ đây có thể là một vấn đề với trình biên dịch, đặc biệt là nó chỉ xảy ra với trình biên dịch cụ thể này. Tôi đang sử dụng mingw32 trên Windows7:
> gcc.exe --version
gcc version 4.4.0 (GCC)
Dưới đây là trích đoạn trích đoạn của các phần liên quan của Box2D. Bạn có thể kiểm tra nguồn gốc đầy đủ tại địa chỉ:
b2Shape.h
b2CircleShape.h
b2CircleShape.cpp
SensorTest.h
//base class
class b2Shape
{
public:
virtual ~b2Shape() {}
virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0;
};
//sub class
class b2CircleShape : public b2Shape
{
public:
b2CircleShape();
b2Shape* Clone(b2BlockAllocator* allocator) const;
};
inline b2CircleShape::b2CircleShape() {}
b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const
{
void* mem = allocator->Allocate(sizeof(b2CircleShape));
b2CircleShape* clone = new (mem) b2CircleShape;
*clone = *this;
return clone;
}
Lưu ý vị trí mới trong hàm Clone.
Bây giờ thực hiện điều đó gây ra vấn đề nắm này:
{
b2CircleShape shape;
shape.Clone(allocator); //ok
}
{
b2CircleShape shape;
shape.Clone(allocator); //"pure virtual method called"
}
Sau khi giáo dục bản thân mình về cách một phương pháp ảo bao giờ có thể được gọi ở nơi đầu tiên, tôi đã cố gắng để tìm ra lý do tại sao nó đang xảy ra ở đây , vì nó không phù hợp với trường hợp cổ điển gọi một hàm ảo trong hàm tạo lớp cơ sở. Sau một phiên kéo dài một cách mù quáng xung quanh một cách mù quáng, tôi đã đưa ra trường hợp tối thiểu ở trên.
Đoán ngẫu nhiên của tôi là trình biên dịch đủ thông minh để thấy rằng hai phiên bản b2CircleShape này không được sử dụng trong cùng phạm vi, vì vậy nó chỉ phân bổ không gian cho một và tái sử dụng nó. Sau khi trường hợp đầu tiên bị hủy, vtable như mong đợi, được hosed. Sau đó, đối với một số lý do khi dụ thứ hai được xây dựng, vtable không được xây dựng lại ...?
Tôi đã đưa ra hai điều để tránh sự cố, nhưng giống như tôi nói có vẻ như vấn đề trình biên dịch hơn nên tôi không đề xuất mã này cần được thay đổi.
Sửa chữa đáng ngờ số 1 là để nhận xét định nghĩa phá hủy ảo trong lớp cơ sở. Tất cả các thông tin tôi đã đọc về chủ đề này cho thấy đây không phải là câu trả lời. Tôi thích rằng trình biên dịch sẽ cung cấp một destructor mặc định ~ b2Shape() {} nếu không có gì được chỉ định, vậy tại sao kết quả lại khác nhau nếu tôi thực sự chỉ định những gì mặc định sẽ được anyway? Vâng, điều này là bên cạnh điểm thực sự ...)
Không đáng ngờ sửa chữa số 2 Tôi phát hiện ra là để loại bỏ 'nội tuyến' từ constructor sub-class . Có lẽ có một cái gì đó về vị trí mới, xây dựng nội tuyến và các trường hợp tái sử dụng trong cùng một khung ngăn xếp mà không chơi độc đáo với nhau. Một số nghiên cứu khác cho tôi biết rằng trình biên dịch tự do làm bất cứ điều gì nó thích về đề xuất 'nội tuyến', vì vậy có lẽ các trình biên dịch khác không có vấn đề này bởi vì họ đang bỏ qua 'nội tuyến'?
Bạn có thể cho chúng tôi biết người phân bổ thực sự là gì không? Bạn có cơ hội phân bổ theo giá trị cho hàm nhân bản không? – Arunmu
Nguồn có thể tìm thấy tại đây. http://code.google.com/p/box2d/source/browse/trunk/Box2D/Box2D/Common/ Có vẻ như trình phân bổ không liên quan mặc dù vì tôi có thể sử dụng tính năng 'mới' điển hình hơn trong hàm Clone với cùng một kết quả. – iforce2d
Chết tiệt, mã C trong C++ ngụy trang: x Tôi cho rằng bạn biết bạn đang rò rỉ bộ nhớ? (Có nó không liên quan, nhưng tôi không thể nghĩ ra bất cứ điều gì trong đoạn mã được trình bày để tạo ra hành vi như vậy). Và đối với một bình luận có liên quan: lắp ráp được tạo ra cho phương pháp được xem xét là gì? –