【发布时间】:2022-07-20 16:37:34
【问题描述】:
我最近了解了链接时间优化in a C++ Weekly episode。我认为在我的代码中使用 LTO 是个好主意,所以我决定使用标志 -flto 和 -fno-fat-lto-objects。不幸的是,我开始收到此警告
data_array.hpp:29:50: warning: argument 1 value ‘18446744073709551615’ exceeds maximum object size 9223372036854775807 [-Walloc-size-larger-than=]
29 | m_data = m_size == 0 ? nullptr : new T[m_size];
| ^
data_array.hpp: In function ‘main’:
/usr/include/c++/11/new:128:26: note: in a call to allocation function ‘operator new []’ declared here
128 | _GLIBCXX_NODISCARD void* operator new[](std::size_t) _GLIBCXX_THROW (std::bad_alloc)
| ^
我在 Ubuntu 20.04 上使用 g++(版本 g++ (Ubuntu 11.1.0-1ubuntu1~20.04) 11.1.0)。
我正在使用的实际代码是here,但是它太大了,我为这篇文章准备了一个工作示例(见下文),它重新创建了原始上下文。
问题
-
有人可以帮我理解为什么会出现这个警告吗?我认为,当代码合并时,编译器认为
new是用未初始化的值调用的。但这不是真的:数组的内存总是分配有m_size初始化的,无论是正好为0(由空构造函数确保)还是用户提供的其他值,都应该初始化(如下面的代码所示)。 -
只有在初始化
data_array<data_array<int>>类型的对象时才会出现警告。内部的data_array<int>应该用m_size=0初始化,因为这是空构造函数的作用。但是在初始化data_array<int>类型的对象时不会出现警告。为什么? -
有人能告诉我这是否会导致未定义的行为,即使
m_size实际初始化了?我通常会努力以一种从未发出警告的方式编写代码。我应该忽略这个警告,还是添加一个简单地使其静音的标志?如果没有,我该如何解决?
重现代码
首先,包含警告中的行的类是这个 C 数组的自定义实现。
#pragma once
#include <algorithm>
template <typename T>
struct data_array {
public:
data_array() noexcept = default;
data_array(const std::size_t n) noexcept { m_size = n; alloc_data(); }
~data_array() noexcept { clear(); }
void clear() noexcept {
delete[] m_data;
m_size = 0;
m_data = nullptr;
}
void resize(std::size_t new_size) noexcept {
if (new_size != m_size or m_data == nullptr) {
delete[] m_data;
m_size = new_size;
alloc_data();
}
}
std::size_t size() const noexcept { return m_size; }
T& operator[] (const std::size_t i) noexcept { return m_data[i]; }
const T& operator[] (const std::size_t i) const noexcept { return m_data[i]; }
private:
void alloc_data() noexcept {
m_data = m_size == 0 ? nullptr : new T[m_size];
}
protected:
T *m_data = nullptr;
std::size_t m_size = 0;
};
(我将代码压缩了一点,我通常不会这样编码)。 包含 main 的文件如下:
#include <iostream>
#include "data_array.hpp"
class complicated_object_base {
public:
std::size_t get_size1() const noexcept { return m_vec1.size(); }
void set_size1(std::size_t size) noexcept { m_vec1.resize(size); }
private:
std::vector<std::size_t> m_vec1;
};
class complicated_object : public complicated_object_base {
public:
std::size_t get_size2() const noexcept { return m_vec2.size(); }
void set_size2(std::size_t size) noexcept { m_vec2.resize(size); }
private:
std::vector<std::size_t> m_vec2;
};
class my_class {
public:
my_class(const complicated_object& co) noexcept
: m_co(co),
m_data(m_co.get_size1()),
m_data2(m_co.get_size1())
{ }
~my_class() noexcept { }
void initialize() noexcept {
for (std::size_t i = 0; i < m_data.size(); ++i) {
m_data2[i] = i;
m_data[i].resize(m_co.get_size2());
for (std::size_t j = 0; j < m_data[i].size(); ++j) {
m_data[i][j] = 3;
}
}
}
std::size_t get_sum() const noexcept {
std::size_t S = 0;
for (std::size_t i = 0; i < m_data.size(); ++i) {
S += m_data2[i];
for (std::size_t j = 0; j < m_data[i].size(); ++j) {
S += m_data[i][j];
}
}
return S;
}
private:
const complicated_object& m_co;
data_array<data_array<std::size_t>> m_data;
data_array<std::size_t> m_data2;
};
int main() {
complicated_object co;
co.set_size1(100);
co.set_size2(234);
my_class mc(co);
mc.initialize();
std::cout << mc.get_sum() << '\n';
}
生成文件
CXXFLAGS = -pipe -std=c++17 -fPIC -fopenmp -flto -fno-fat-lto-objects -O3 -Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wunused -Woverloaded-virtual -Wpedantic -Wconversion -Wsign-conversion -Wnull-dereference -Wdouble-promotion -Wformat=2 -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wuseless-cast -Wrestrict -UDEBUG -DNDEBUG -fstrict-aliasing -D_REENTRANT -fPIC
LFLAGS = -fPIC -O3 -flto -fno-fat-lto-objects -DNDEBUG -UDEBUG -Wl,-O3
main: main.o
g++ $(LFLAGS) -o main main.o
main.o: main.cpp data_array.hpp
g++ $(CXXFLAGS) -c main.cpp
clean:
rm -f main *.o
【问题讨论】:
-
您是否从 MWE 收到同样的警告?这里没有警告:godbolt.org/z/vbn6hhfvE
-
顺便说一句,M 代表 Minimal,当警告在
m_data = m_size == 0 ? nullptr : new T[m_size];行中时,不需要更多代码来重新创建警告 -
@463035818_is_not_a_number 它确实重现。 godbolt.org/z/9fdvxqn7e
-
@463035818_is_not_a_number 该警告仅在使用 LTO 时出现。没有它就没有警告。此外,如果没有
complicated_object类中的继承,我无法重新创建警告。这激发了(相当)长的“M”WE -
@Nimrod 谢谢。我将编译器更改为12.1,它没有出现。也许 11.1 有错误?
标签: c++ c++17 compiler-optimization