奇怪的lambda问题(编译器错误?
Odd lambda issue (compiler bug?)
我有一段代码在运行时失败,存在各种奇怪的内存损坏问题。 我已将其缩小到以下代码部分:
List<CollisionBlock> WorldClient::getCollisionBlocks(RectF const& boundBox, bool doSort, Vec2F sortCenter) const {
auto res = m_collisionGenerator.getPolys(boundBox);
if (doSort) {
sort(res, [=](CollisionBlock const& block1, CollisionBlock const& block2) {
return magSquared(sortCenter - block1.poly.center()) < magSquared(sortCenter - block2.poly.center());
});
}
return res;
}
如果我从 lambda 中删除const&
,代码工作正常。 我不知道为什么。 我想知道我是否遇到了编译器错误,或者是否有一些明显的东西被我忽略了。
以下是CollisionBlock的定义:
struct CollisionBlock {
PolyF poly;
// Will never be None
CollisionKind kind;
// Normalzied vector encoding the slope of the block we collided with.
// Always faces right, y component can be positive or negative.
Vec2F slope;
};
我可以在 Linux 32 位(g++ 版本 4.7.0 和 4.6.3)、MacOSX(不确定字大小和 g++ 版本)、Windows 7 64 位(g++ 版本 4.6.3)、Windows 7 32 位(g++ 版本 4.6.2 和 4.6.3)上重现,但不能在 Linux 64 位(g++ 版本 4.6.1)上重现。
我使用的是 C++11,而不是提升。
Poly::center()
Coord center() const {
return sum(m_vertexes) / (DataType)m_vertexes.size();
}
sum
template<typename Container>
typename Container::value_type sum(Container const& cont) {
return reduce(cont, std::plus<typename Container::value_type>());
}
reduce
// Somewhat nicer form of std::accumulate
template<typename Container, typename Function>
typename Container::value_type reduce(Container const& l, Function f) {
typename Container::const_iterator i = l.begin();
typename Container::value_type res{};
if (i == l.end())
return res;
res = *i++;
while (i != l.end())
res = f(res, *i++);
return res;
}
sort
template<typename Container, typename Compare>
void sort(Container& c, Compare comp) {
std::sort(c.begin(), c.end(), comp);
}
这个问题有很多事情要做。 抱歉,我将尝试制定一个较小的测试用例。
更新:
将Poly::center
中的sum
调用替换为std::accumulate
无济于事。
我相当确定错误超出了您发布的代码。 你可以把我的虚拟代码放在下面,慢慢地把它变成你的真实代码,直到它开始出现问题。如果您找到它,请告诉我们,我很好奇。
仅供参考,我不得不在几个地方编写代码才能接近您正在做的事情。 所有这些真正做的是练习你发布的一小段代码。
#include <list>
#include <deque>
#include <vector>
#include <algorithm>
typedef double mocish;
typedef int CollisionKind; //is actually enum class
typedef mocish RectF;
class Vec2F {
public:
Vec2F() {
vertexes.push_back(0);
vertexes.push_back(0);
}
Vec2F(float a, float b) {
vertexes.push_back(a);
vertexes.push_back(b);
}
float operator[](unsigned index) const {
return vertexes[index];
}
float operator[](unsigned index) {
return vertexes[index];
}
Vec2F operator+(Vec2F const& other) const {
return Vec2F(vertexes[0]+other[0], vertexes[1]+other[1]);
}
Vec2F operator-(Vec2F const& other) const {
return Vec2F(vertexes[0]-other[0], vertexes[1]-other[1]);
}
Vec2F operator*(float other) const {
return Vec2F(vertexes[0]*other, vertexes[1]*other);
}
Vec2F operator/(float other) const {
return Vec2F(vertexes[0]/other, vertexes[1]/other);
}
Vec2F operator=(Vec2F const& other) {
vertexes[0] = other[0];
vertexes[1] = other[1];
return *this;
}
private:
std::deque<float> vertexes;
};
float magSquared(Vec2F const& a) {
return a[0]*a[0]+a[1]*a[1];
}
typedef Vec2F Coord;
// Somewhat nicer form of std::accumulate
template<typename Container, typename Function>
typename Container::value_type reduce(Container const& l, Function f) {
typename Container::const_iterator i = l.begin();
typename Container::value_type res{};
if (i == l.end())
return res;
res = *i++;
while (i != l.end())
res = f(res, *i++);
return res;
}
template<typename Container>
typename Container::value_type sum(Container const& cont) {
return reduce(cont, std::plus<typename Container::value_type>());
}
struct PolyF
{
PolyF()
{
m_vertexes.resize(4);
std::generate( m_vertexes.begin(), m_vertexes.end(), [](){ return Vec2F(std::rand(), std::rand());} );
}
std::vector<Coord> m_vertexes;
Coord center() const
{
return sum(m_vertexes) / (float)m_vertexes.size();
}
};
struct CollisionBlock
{
PolyF poly;
// Will never be None
CollisionKind kind;
// Normalzied vector encoding the slope of the block we collided with.
// Always faces right, y component can be positive or negative.
Vec2F slope;
};
template<typename Container, typename Compare>
void sort(Container& c, Compare comp) {
std::sort(c.begin(), c.end(), comp);
}
struct CollisionGen
{
std::deque<CollisionBlock> getPolys( RectF const& ) const
{
std::deque<CollisionBlock> collision_block_moc(50);
return collision_block_moc;
}
};
struct WorldClient
{
CollisionGen m_collisionGenerator;
std::deque<CollisionBlock> getCollisionBlocks(RectF const& boundBox, bool doSort, Vec2F sortCenter) const
{
auto res = m_collisionGenerator.getPolys(boundBox);
//auto test = magSquared(sortCenter - res.front().poly.center()) < magSquared(sortCenter - res.front().poly.center());
if (doSort) {
sort(res, [=](CollisionBlock const& block1, CollisionBlock const& block2) {
return magSquared(sortCenter - block1.poly.center()) < magSquared(sortCenter - block2.poly.center());
});
}
return res;
}
};
int main()
{
WorldClient wc;
while (true) {
wc.getCollisionBlocks( 42.0, true, {0,0} );
}
}
我的猜测是模板列表中的迭代器<>不是随机访问迭代器,std::sort 需要,请注意,std::list 仅提供双向迭代。
如果你已经实现了自己的列表,我建议仔细检查你的迭代器实现,以确保它是正确的,并提供随机访问迭代器概念的完整和正确的实现。
我注意到您通过说 [=] 但使用引用将值传递给 lambda。要么应该更改它,要么使用 std::ref 传递值,以真正使用对实例本身的预期引用。
您的比较器是严格的弱阶吗? 它是否一致地对其输入进行排序? 我怀疑你实际上并没有在reduce
中初始化res
,所以center()
最终会返回垃圾。 这应该很容易检查:在 res声明后立即添加一个assert(f(res,res) == res)
。
如果比较器不一致,则在使用 std::sort
时会遇到未定义的行为,这很容易导致崩溃。 并对平台、优化等敏感。
- MSVC多行宏编译器错误
- 静态数据成员的问题-修复链接错误会导致编译器错误
- C++,我收到一个无法理解的编译器错误
- 我收到同义重复编译器错误。我应该如何修复"类型"X"的参数与类型"X"的参数不兼容?
- 重载方法的方式会在使用临时调用时生成编译器错误
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- 编译器错误:destuctor 的更宽松的抛出说明符
- Android NDK clang 编译器错误在 Windows 上显示'No such file or directory'
- C++ G++ 编译器 - 错误:隐式声明的定义
- 这个失败的测试是将零添加到空指针未定义的行为、编译器错误还是其他什么?
- 模板模板参数和模板别名:编译器错误?
- C++ 编译器错误:P1LinkedList.cpp:145:错误:重载的"to_string(int&)"调用不明确
- 在gcc中意外调用了Const重载.编译器错误或兼容性修复程序
- C1001内部编译器错误是由于矢量初始化(如数组)引起的
- 编译器错误(英特尔并行工作室 2019 与 Visual Studio 社区 2019)
- 如何在C++中克服此 C4430 编译器错误?
- 尝试使用 WinBGI 显示文本时出现编译器错误
- 使用typedef'ed返回类型声明友元函数时出现编译器错误
- 如何在类模板的成员函数中正确调用函数对象?正在生成 Visual Studio 编译器错误 C2440
- C++自定义分配器大小参数作为模板参数会引发编译器错误