STL向量上出现奇怪的复制构造函数错误

Weird copy constructor error on STL vector

本文关键字:复制 构造函数 错误 向量 STL      更新时间:2023-10-16

所以我目前正在完成我的物理引擎,我很难弄清楚类出了什么问题,以及为什么编译器报告其复制构造函数在使用向量时被删除。


这是我的课

const real baumgarteCoef = 0.5f;
// based on GoblinPhysics'
// https://github.com/chandlerprall/GoblinPhysics/blob/master/src/classes/Constraints/ContactConstraint.js
class ContactConstraint : public Constraint {
public:
ContactConstraint(PhysicalObject* objA, PhysicalObject* objB, const Vector3& position,
const Vector3& normal, real penetration)
: Constraint(objA, objB, (u32)1) {
collisionPosition = position;
collisionNormal = normal;
this->penetration = penetration;
real r1 = objA->getRestitution();
real r2 = objB->getRestitution();
restitutionCoef = Math::SquareRoot(r1 * r2);
rows[0].lowerLimit = 0.f;
rows[0].upperLimit = Math::PositiveInfinity;
collisionPosA = objA->getInverseRotation().rotate(position - objA->getPosition() +
normal * penetration);
collisionPosB = objB->getInverseRotation().rotate(position - objB->getPosition() -
normal * penetration);
}
ContactConstraint(const ContactConstraint& c) = default;
void update(real timeElapsed) {
auto& row = rows[0];
if (objA->isStatic()) {
row.jacobian[0] = 0.f;
row.jacobian[1] = 0.f;
row.jacobian[2] = 0.f;
row.jacobian[3] = 0.f;
row.jacobian[4] = 0.f;
row.jacobian[5] = 0.f;
} else {
row.jacobian[0] = -collisionNormal.x();
row.jacobian[1] = -collisionNormal.y();
row.jacobian[2] = -collisionNormal.z();
Vector3 v = collisionPosition - objA->getPosition();
Vector3 v2 = v.cross(collisionNormal);
row.jacobian[3] = -v2.x();
row.jacobian[4] = -v2.y();
row.jacobian[5] = -v2.z();
}
if (objB->isStatic()) {
row.jacobian[6] = 0.f;
row.jacobian[7] = 0.f;
row.jacobian[8] = 0.f;
row.jacobian[9] = 0.f;
row.jacobian[10] = 0.f;
row.jacobian[11] = 0.f;
} else {
row.jacobian[6] = collisionNormal.x();
row.jacobian[7] = collisionNormal.y();
row.jacobian[8] = collisionNormal.z();
Vector3 v = collisionPosition - objB->getPosition();
Vector3 v2 = v.cross(collisionNormal);
row.jacobian[9] = v2.x();
row.jacobian[10] = v2.y();
row.jacobian[11] = v2.z();
}
// Apply penetration error.
row.bias = baumgarteCoef * penetration / timeElapsed;
// Apply restitution
Vector3 velocity = objA->getLinearVelocity() +
collisionPosA.cross(objA->getAngularVelocity()) -
objB->getLinearVelocity() - collisionPosB.cross(objB->getAngularVelocity());
real restitution = (collisionNormal.dot(velocity)) * restitutionCoef;
row.bias += restitution;
}
private:
Vector3 collisionPosition;
Vector3 collisionNormal;
Vector3 collisionPosA;
Vector3 collisionPosB;
real penetration;
real restitutionCoef;
};

及其父类

// based on GoblinPhysics'
// https://github.com/chandlerprall/GoblinPhysics/blob/master/src/classes/Constraints/ConstraintRow.js
class Constraint {
public:
class Row {
public:
Constraint* parent;
real jacobian[12];
real derivedMass[12];
real effectiveMass;
real lowerLimit;
real upperLimit;
real bias;
real multiplier;
real multiplierCache;
real eta;
void computeDerivedMass();
void computeEffectiveMass();
void computeEta(real timeDelta);
};
Constraint(PhysicalObject* objectA, PhysicalObject* objectB, u32 numRows) {
objA = objectA;
objB = objectB;
rows = std::make_unique<Row[]>(numRows);
this->numRows = numRows;
for (u32 i = 0; i < numRows; i++)
rows[i].parent = this;
breakingThreshold = 0.f;
active = true;
}
Constraint(const Constraint& c) = default;
PhysicalObject* objA;
PhysicalObject* objB;
std::unique_ptr<Row[]> rows;
Vector3 lastImpulse;
u32 numRows;
real breakingThreshold;
bool active;
virtual void update(real timeElapsed) = 0;
};

错误(上帝保佑,编译器本可以浓缩它(

[  9%] Building CXX object src/CMakeFiles/kepler3d.dir/PhysicsEngine/PhysicsEngine.cpp.obj
In file included from D:/msys64/mingw64/include/c++/7.3.0/memory:64:0,
from D:/msys64/home/ferna/Kepler3D/src/Architecture/Command.h: ,
from D:/msys64/home/ferna/Kepler3D/src/Architecture/Architecture.h:3,
from D:/msys64/home/ferna/Kepler3D/src/PhysicsEngine/PhysicsEngine.cpp:2:
D:/msys64/mingw64/include/c++/7.3.0/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = Kepler3D::ContactConstraint; _Args = {Kepler3D::ContactConstraint}]':
D:/msys64/mingw64/include/c++/7.3.0/bits/stl_uninitialized.h:83:18:   required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<Kepler3D::ContactConstraint*>; _ForwardIterator = Kepler3D::ContactConstraint*; bool _TrivialValueTypes = false]'
D:/msys64/mingw64/include/c++/7.3.0/bits/stl_uninitialized.h:134:15:   required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<Kepler3D::ContactConstraint*>; _ForwardIterator = Kepler3D::ContactConstraint*]'
D:/msys64/mingw64/include/c++/7.3.0/bits/stl_uninitialized.h:289:37:   required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<Kepler3D::ContactConstraint*>; _ForwardIterator = Kepler3D::ContactConstraint*; _Tp = Kepler3D::ContactConstraint]'
D:/msys64/mingw64/include/c++/7.3.0/bits/stl_uninitialized.h:311:2:   required from '_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = Kepler3D::ContactConstraint*; _ForwardIterator = Kepler3D::ContactConstraint*; _Allocator = std::allocator<Kepler3D::ContactConstraint>]'
D:/msys64/mingw64/include/c++/7.3.0/bits/vector.tcc:426:6:   required from 'void std::vector<_Tp, _Alloc>::_M_realloc_insert(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {Kepler3D::PhysicalObject*&, Kepler3D::PhysicalObject*&, const Kepler3D::Vector3&, const Kepler3D::Vector3&, float&}; _Tp = Kepler3D::ContactConstraint; _Alloc = std::allocator<Kepler3D::ContactConstraint>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<Kepler3D::ContactConstraint*, std::vector<Kepler3D::ContactConstraint> >; typename std::_Vector_base<_Tp, _Alloc>::pointer = Kepler3D::ContactConstraint*]'
D:/msys64/mingw64/include/c++/7.3.0/bits/vector.tcc:105:21:   required from 'std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {Kepler3D::PhysicalObject*&, Kepler3D::PhysicalObject*&, const Kepler3D::Vector3&, const Kepler3D::Vector3&, float&}; _Tp = Kepler3D::ContactConstraint; _Alloc = std::allocator<Kepler3D::ContactConstraint>; std::vector<_Tp, _Alloc>::reference = Kepler3D::ContactConstraint&]'
D:/msys64/home/ferna/Kepler3D/src/PhysicsEngine/Dynamics/ConstraintsManager.h:23:82:   required from here
D:/msys64/mingw64/include/c++/7.3.0/bits/stl_construct.h:75:7: error: use of deleted function 'Kepler3D::ContactConstraint::ContactConstraint(const Kepler3D::ContactConstraint&)'
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }

我不确定父类上的唯一指针是否使复制构造函数无法派生。我还想补充一点,在任何情况下,我都不会直接复制类(只复制模板(,但是,由于向量类的内部机制,复制是默认的。


此行导致ConstraintsManager错误

contactConstraints.emplace_back(objA, objB, position, normal, penetration);

不能复制包含unique_ptr的对象,因为默认情况下该成员(即rows(不可复制。如果需要副本,您必须提供自己的实现。

据我所知,通过查看错误跟踪,我认为您应该能够移动对象。你试过提供默认的移动构造函数吗?

Constraint(Constraint&& c) = default;

我认为它也需要是noexcept

我不确定你的派生类是否可以被复制和/或移动,因为我没有Vector3的定义。

从错误跟踪中可以明显看出,您需要能够复制(或移动(项,因为在矢量已满时添加项时,可能需要调整其大小。

尽管我相信在这个例子中您需要深度复制,但在某些情况下,您可能能够存储shared_ptr而不是unique_ptr,然后您将自动生成一个浅复制构造函数。

事实上,它可能在这里也能工作,但您需要小心,不要进行意外复制,然后在没有意识到数据在这些对象之间部分共享的情况下修改对象。

发现问题。事实证明,由于父类具有unique_ptr,因此无法派生复制构造函数,一个简单的解决方案是,我使用std::vector来代替为我的数组生成unique_ptr。

为了将来参考,unique_ptrs没有副本构造函数,必须根据具体情况进行处理。