为什么编译器会在某些优化级别警告未初始化的边迭代器?
Why does the compiler warn about uninitialized edge iterator in some optimization levels?
我已经尽可能地减少了可重现的例子。在其中,我遍历了增强图中的所有边,并收到了我不理解的警告。请向我解释为什么我会收到此警告,也许还有为什么它只出现在某些优化级别。
/*
* reproducing the warning about maybe uninitialized edge iterator
*/
#include <vector>
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
typedef boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS> traits;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, boost::no_property,
boost::property<boost::edge_capacity_t, long>> graph;
typedef traits::vertex_descriptor vertex_desc;
typedef traits::edge_descriptor edge_desc;
typedef boost::graph_traits<graph>::edge_iterator edge_iterator;
int main(){
// build a graph
graph G(10);
// get its capacity map
auto c_map = boost::get(boost::edge_capacity, G);
// get a handle to the first vertex
vertex_desc source = boost::vertex(0, G);
// add an edge, with a capacity of 1
edge_desc e = boost::add_edge(boost::vertex(0, G), boost::vertex(1, G), G).first;
c_map[e] = 1;
// loop over all edges in the graph
std::pair<edge_iterator, edge_iterator> eip = boost::edges(G);
for (edge_iterator eit = eip.first; eit != eip.second; eit++){
edge_desc e = *eit;
vertex_desc a = boost::source(e, G);
vertex_desc b = boost::target(e, G);
bool source_involved = ((a == source) || (b == source));
std::cout << (source_involved ? "yes" : "no") << std::endl;
}
}
用-O0
或-O1
编译,没有警告:
g++ -std=c++14 -Wall -Wextra -O0 repro.cpp -o repro.exe
使用 -O2
编译我收到此警告:
# g++ -std=c++14 -Wall -Wextra -O2 repro.cpp -o repro.exe
repro.cpp: In function 'int main()':
repro.cpp:28:24: warning: '*((void*)& eit +48)' may be used uninitialized in this function [-Wmaybe-uninitialized]
for (edge_iterator eit = eip.first; eit != eip.second; eit++){
^~~
并使用 -O3
、-O4
、-O5
进行编译,我收到了类似的警告,但很丑陋:
# g++ -std=c++14 -Wall -Wextra -O3 repro.cpp -o repro.exe
repro.cpp: In function 'int main()':
repro.cpp:28:24: warning: '*((void*)(& eit)+32).__gnu_cxx::__normal_iterator<boost::detail::stored_edge_property<long unsigned int, boost::property<boost::edge_capacity_t, long int> >*, std::vector<boost::detail::stored_edge_property<long unsigned int, boost::property<boost::edge_capacity_t, long int> >, std::allocator<boost::detail::stored_edge_property<long unsigned int, boost::property<boost::edge_capacity_t, long int> > > > >::_M_current' may be used uninitialized in this function [-Wmaybe-uninitialized]
for (edge_iterator eit = eip.first; eit != eip.second; eit++){
我的g++ --version
是
g++ (Ubuntu 8.4.0-1ubuntu1~18.04) 8.4.0
我 运行 在 docker
# uname -a
Linux 88157d45c773 5.4.0-58-generic #64~18.04.1-Ubuntu SMP Wed Dec 9 17:11:11 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
警告确实出现在 -std=c++11
和 -std=c++14
中,但似乎没有出现在 -std=c++17
中。
这个警告告诉我什么?有什么问题?
正如我评论的那样,这可能是特定编译器版本的编译器问题,其中内联+死代码省略会导致虚假的未使用变量警告。
我认为查找是否有与修复相关的错误报告没有多大好处。相反,让我向您展示用 C++14 编写代码的更优雅的方法。
Not intended as an answer to the question as posed. though by sheer coincidence, the specific warnings you encounter might be gone.
I post the answer for inspiration/educational value as I see a lot of copy/past BGL that is badly behind the times.
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
#include <vector>
using capacity_prop = boost::property<boost::edge_capacity_t, long>;
using graph = boost::adjacency_list<
boost::vecS, boost::vecS, boost::directedS,
boost::no_property, capacity_prop
>;
int main() {
graph G(10);
auto add = [&G](auto a, auto b, auto c) {
add_edge(vertex(a, G), vertex(b, G), capacity_prop{c}, G);
};
add(0, 1, 1);
add(1, 2, 2);
add(1, 3, 3);
add(1, 7, 4);
add(1, 8, 5);
add(2, 5, 6);
add(5, 3, 7);
add(5, 0, 8);
add(7, 0, 9);
auto const s = vertex(0, G);
for (auto e : boost::make_iterator_range(edges(G))) {
auto a = source(e, G);
auto b = target(e, G);
std::cout << e << " involves " << s << "? "
<< std::boolalpha << (a == s || b == s) << std::endl;
}
}
版画
(0,1) involves 0? true
(1,2) involves 0? false
(1,3) involves 0? false
(1,7) involves 0? false
(1,8) involves 0? false
(2,5) involves 0? false
(5,3) involves 0? false
(5,0) involves 0? true
(7,0) involves 0? true
C++17 奖金
写初始化代码会更自然更容易
for (auto [a,b,c] : { std::tuple
{0, 1, 1}, {1, 2, 2}, {1, 3, 3},
{1, 7, 4}, {1, 8, 5}, {2, 5, 6},
{5, 3, 7}, {5, 0, 8}, {7, 0, 9}, })
{
add_edge(vertex(a, G), vertex(b, G), capacity_prop{c}, G);
}
逻辑奖励
如果你真的只想找到涉及顶点 s
的边集,你可以这样写并且可能更有效:
auto const s = vertex(2, G); // different example
auto [f,l] = out_edges(s, G);
edge_set involved(f, l);
for (auto e : make_iterator_range(edges(G)))
if (target(e, G) == s)
involved.insert(e);
for (auto e : involved)
std::cout << e << " ";
版画
(1,2) (2,5)
正如人们所期望的那样。
性能提示
如果您可以调整图形模型,通过更改它以保持 adjacency_list:
的双向边,可以获得更好的性能
std::set<graph::edge_descriptor> involved;
auto insert = [&](auto range) { involved.insert(range.first, range.second); };
insert(out_edges(s, G));
insert(in_edges(s, G));
或者,实际上,直接打印它们:
for (auto e : make_iterator_range(out_edges(s, G)))
std::cout << e << " ";
for (auto e : make_iterator_range(in_edges(s, G)))
std::cout << e << " ";
打印相同。
Whether or not this improves performance for your application depends mostly on whether you have more mutations or more queries on the graph.
PS
这是我为示例制作的图表以供参考
这是
的结果
boost::dynamic_properties dp;
dp.property("node_id", get(boost::vertex_index, G));
dp.property("label", get(boost::edge_capacity, G));
write_graphviz_dp(std::cout, G, dp);
并使用 dot
(例如 online)
我已经尽可能地减少了可重现的例子。在其中,我遍历了增强图中的所有边,并收到了我不理解的警告。请向我解释为什么我会收到此警告,也许还有为什么它只出现在某些优化级别。
/*
* reproducing the warning about maybe uninitialized edge iterator
*/
#include <vector>
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
typedef boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS> traits;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, boost::no_property,
boost::property<boost::edge_capacity_t, long>> graph;
typedef traits::vertex_descriptor vertex_desc;
typedef traits::edge_descriptor edge_desc;
typedef boost::graph_traits<graph>::edge_iterator edge_iterator;
int main(){
// build a graph
graph G(10);
// get its capacity map
auto c_map = boost::get(boost::edge_capacity, G);
// get a handle to the first vertex
vertex_desc source = boost::vertex(0, G);
// add an edge, with a capacity of 1
edge_desc e = boost::add_edge(boost::vertex(0, G), boost::vertex(1, G), G).first;
c_map[e] = 1;
// loop over all edges in the graph
std::pair<edge_iterator, edge_iterator> eip = boost::edges(G);
for (edge_iterator eit = eip.first; eit != eip.second; eit++){
edge_desc e = *eit;
vertex_desc a = boost::source(e, G);
vertex_desc b = boost::target(e, G);
bool source_involved = ((a == source) || (b == source));
std::cout << (source_involved ? "yes" : "no") << std::endl;
}
}
用-O0
或-O1
编译,没有警告:
g++ -std=c++14 -Wall -Wextra -O0 repro.cpp -o repro.exe
使用 -O2
编译我收到此警告:
# g++ -std=c++14 -Wall -Wextra -O2 repro.cpp -o repro.exe
repro.cpp: In function 'int main()':
repro.cpp:28:24: warning: '*((void*)& eit +48)' may be used uninitialized in this function [-Wmaybe-uninitialized]
for (edge_iterator eit = eip.first; eit != eip.second; eit++){
^~~
并使用 -O3
、-O4
、-O5
进行编译,我收到了类似的警告,但很丑陋:
# g++ -std=c++14 -Wall -Wextra -O3 repro.cpp -o repro.exe
repro.cpp: In function 'int main()':
repro.cpp:28:24: warning: '*((void*)(& eit)+32).__gnu_cxx::__normal_iterator<boost::detail::stored_edge_property<long unsigned int, boost::property<boost::edge_capacity_t, long int> >*, std::vector<boost::detail::stored_edge_property<long unsigned int, boost::property<boost::edge_capacity_t, long int> >, std::allocator<boost::detail::stored_edge_property<long unsigned int, boost::property<boost::edge_capacity_t, long int> > > > >::_M_current' may be used uninitialized in this function [-Wmaybe-uninitialized]
for (edge_iterator eit = eip.first; eit != eip.second; eit++){
我的g++ --version
是
g++ (Ubuntu 8.4.0-1ubuntu1~18.04) 8.4.0
我 运行 在 docker
# uname -a
Linux 88157d45c773 5.4.0-58-generic #64~18.04.1-Ubuntu SMP Wed Dec 9 17:11:11 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
警告确实出现在 -std=c++11
和 -std=c++14
中,但似乎没有出现在 -std=c++17
中。
这个警告告诉我什么?有什么问题?
正如我评论的那样,这可能是特定编译器版本的编译器问题,其中内联+死代码省略会导致虚假的未使用变量警告。
我认为查找是否有与修复相关的错误报告没有多大好处。相反,让我向您展示用 C++14 编写代码的更优雅的方法。
Not intended as an answer to the question as posed. though by sheer coincidence, the specific warnings you encounter might be gone.
I post the answer for inspiration/educational value as I see a lot of copy/past BGL that is badly behind the times.
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
#include <vector>
using capacity_prop = boost::property<boost::edge_capacity_t, long>;
using graph = boost::adjacency_list<
boost::vecS, boost::vecS, boost::directedS,
boost::no_property, capacity_prop
>;
int main() {
graph G(10);
auto add = [&G](auto a, auto b, auto c) {
add_edge(vertex(a, G), vertex(b, G), capacity_prop{c}, G);
};
add(0, 1, 1);
add(1, 2, 2);
add(1, 3, 3);
add(1, 7, 4);
add(1, 8, 5);
add(2, 5, 6);
add(5, 3, 7);
add(5, 0, 8);
add(7, 0, 9);
auto const s = vertex(0, G);
for (auto e : boost::make_iterator_range(edges(G))) {
auto a = source(e, G);
auto b = target(e, G);
std::cout << e << " involves " << s << "? "
<< std::boolalpha << (a == s || b == s) << std::endl;
}
}
版画
(0,1) involves 0? true
(1,2) involves 0? false
(1,3) involves 0? false
(1,7) involves 0? false
(1,8) involves 0? false
(2,5) involves 0? false
(5,3) involves 0? false
(5,0) involves 0? true
(7,0) involves 0? true
C++17 奖金
写初始化代码会更自然更容易
for (auto [a,b,c] : { std::tuple
{0, 1, 1}, {1, 2, 2}, {1, 3, 3},
{1, 7, 4}, {1, 8, 5}, {2, 5, 6},
{5, 3, 7}, {5, 0, 8}, {7, 0, 9}, })
{
add_edge(vertex(a, G), vertex(b, G), capacity_prop{c}, G);
}
逻辑奖励
如果你真的只想找到涉及顶点 s
的边集,你可以这样写并且可能更有效:
auto const s = vertex(2, G); // different example
auto [f,l] = out_edges(s, G);
edge_set involved(f, l);
for (auto e : make_iterator_range(edges(G)))
if (target(e, G) == s)
involved.insert(e);
for (auto e : involved)
std::cout << e << " ";
版画
(1,2) (2,5)
正如人们所期望的那样。
性能提示
如果您可以调整图形模型,通过更改它以保持 adjacency_list:
的双向边,可以获得更好的性能std::set<graph::edge_descriptor> involved;
auto insert = [&](auto range) { involved.insert(range.first, range.second); };
insert(out_edges(s, G));
insert(in_edges(s, G));
或者,实际上,直接打印它们:
for (auto e : make_iterator_range(out_edges(s, G)))
std::cout << e << " ";
for (auto e : make_iterator_range(in_edges(s, G)))
std::cout << e << " ";
打印相同。
Whether or not this improves performance for your application depends mostly on whether you have more mutations or more queries on the graph.
PS
这是我为示例制作的图表以供参考
这是
的结果boost::dynamic_properties dp;
dp.property("node_id", get(boost::vertex_index, G));
dp.property("label", get(boost::edge_capacity, G));
write_graphviz_dp(std::cout, G, dp);
并使用 dot
(例如 online)