$cache[$key] = empty($arr) ? NULL : $arr; return $cache[$key]; } // 门户 获取需要在频道显示的栏目主题数据 function portal_channel_thread($fid) { global $forumlist; if (empty($fid)) return NULL; $orderby = array('tid' => 1); $page = 1; // 遍历所有在频道显示内容的栏目 $category_forumlist = channel_category($fid); $arrlist = array(); $forum_tids = array(); $tidlist = array(); if ($category_forumlist) { foreach ($category_forumlist as &$_forum) { // 频道显示数据 $arrlist['list'][$_forum['fid']] = array( 'fid' => $_forum['fid'], 'name' => $_forum['name'], 'rank' => $_forum['rank'], 'type' => $_forum['type'], 'url' => $_forum['url'], 'channel_new' => $_forum['channel_new'], ); $forum_thread = thread_tid__find(array('fid' => $_forum['fid']), $orderby, $page, $_forum['channel_new'], 'tid', array('tid')); // 最新信息按栏目分组 foreach ($forum_thread as $key => $_thread) { $forum_tids[$key] = $_thread; } unset($forum_thread); } $tidlist += $forum_tids; } unset($category_forumlist); // 获取属性对应的tid集合 list($flaglist, $flagtids) = flag_thread_by_fid($fid); empty($flagtids) || $tidlist += $flagtids; unset($flagtids); // 频道置顶 $stickylist = sticky_list_thread($fid); empty($stickylist) || $tidlist += $stickylist; // 在这之前合并所有二维数组 tid值为键/array('tid值' => tid值) $tidarr = arrlist_values($tidlist, 'tid'); // 在这之前使用$tidarr = array_merge($tidarr, $arr)前合并所有一维数组 tid/array(1,2,3) if (empty($tidarr)) { $arrlist['list'] = isset($arrlist['list']) ? array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid') : array(); return $arrlist; } $tidarr = array_unique($tidarr); $pagesize = count($tidarr); // 遍历获取的所有tid主题 $threadlist = well_thread_find_asc($tidarr, $pagesize); // 遍历时为升序,翻转为降序 $threadlist = array_reverse($threadlist); foreach ($threadlist as &$_thread) { // 各栏目最新内容 isset($forum_tids[$_thread['tid']]) AND $arrlist['list'][$_thread['fid']]['news'][$_thread['tid']] = $_thread; // 全站置顶内容 isset($stickylist[$_thread['tid']]) AND $arrlist['sticky'][$_thread['tid']] = $_thread; // 首页属性主题 if (!empty($flaglist)) { foreach ($flaglist as $key => $val) { if (isset($val['tids']) && in_array($_thread['tid'], $val['tids'])) { $arrlist['flaglist'][$key][array_search($_thread['tid'], $val['tids'])] = $_thread; ksort($arrlist['flaglist'][$key]); $arrlist['flag'][$_thread['tid']] = $_thread; } } } } unset($threadlist); if (isset($arrlist['sticky'])) { $i = 0; foreach ($arrlist['sticky'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flag'])) { $i = 0; foreach ($arrlist['flag'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flaglist'])) { foreach ($arrlist['flaglist'] as &$val) { $i = 0; foreach ($val as &$v) { ++$i; $v['i'] = $i; } } } isset($arrlist['list']) AND $arrlist['list'] = array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid'); return $arrlist; } ?>c++ - Can 'unused variable' optimization prevent an exception? - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - Can 'unused variable' optimization prevent an exception? - Stack Overflow

programmeradmin0浏览0评论

I have the following code:

void check_portvalue(std::string_view value)
{
    [[maybe_unused]] port_t test {value};
}

The object test remains unused, but creation serves as a check, because the constructor can throw. The [[maybe_unused]] attribute suppresses the compiler warning.

But since the compiler detects that this is unused, could it optimize out the entire statement and thus prevent the exception from being thrown ?

I have the following code:

void check_portvalue(std::string_view value)
{
    [[maybe_unused]] port_t test {value};
}

The object test remains unused, but creation serves as a check, because the constructor can throw. The [[maybe_unused]] attribute suppresses the compiler warning.

But since the compiler detects that this is unused, could it optimize out the entire statement and thus prevent the exception from being thrown ?

Share Improve this question edited Feb 6 at 16:28 Tootsie asked Feb 6 at 12:52 TootsieTootsie 8674 silver badges12 bronze badges 5
  • For me it has the smell of a design problem. Perhaps the "test" should happen inside the check_portvalue function instead of being passed on to the port_t constructor? Or perhaps it could be a static member function of port_t, and check_portvalue is just a proxy for that? – Some programmer dude Commented Feb 6 at 12:59
  • 2 If creating (unused) objects has side effects, these can't be optimized away (unless undefined behavior happens somewhere). The creation itself (allocating stack memory, etc) may be optimized away by the as-if-rule. – chtz Commented Feb 6 at 13:05
  • 3 You might use port_t{value}; to avoid [[maybe_unused]]. – Jarod42 Commented Feb 6 at 13:20
  • (void) port_t{value}; maybe? – YSC Commented Feb 6 at 13:50
  • The object test remains unused, but creation serves as a check, because the constructor can throw. To me, this screams of a check-that-throws that should be a freestanding function, and not squirreled away inside a constructor. (The port_t constructor itself could call the freestanding function.) – Eljay Commented Feb 6 at 14:13
Add a comment  | 

2 Answers 2

Reset to default 9

Optimizer has to follow the as-if rule (i.e cannot change "observable behaviors")

The only exception to the as-if rule are:

  • Copy elision
  • the compiler may remove calls to the replaceable allocation functions.

Your code doesn't fall into those categories.

No optimization can remove the call of the constructor in your example. Your example should not actually trigger the warning even without [[maybe_unused]. Moreover, when the function does nothing but create the object you could as well use an unnamed temporary port_t{value}; to the same effect.

The rest of the answer tries to explain this in details.


Consider this example:

#include <iostream>

struct foo {
    foo() { std::cout << "hello"; }
    ~foo() { std::cout << "bye";}
};
    
void bar() {
    foo f = foo();
    std::cout << " x ";
}

int main() { bar(); }

Compling this with warnings enabled (gcc: -Werror -Wall) produces no warnings and the output is (https://godbolt.org/z/TnoPMWbcs):

hello x bye

Actually this RAII (resource allocation is acquisition) pattern is so common in C++ that compilers can easily spot it and will not issue a warning for the unused variable. The "use" of the variable, is to keep the object alive until the end of the scope to have bye appear last. No optimization is allowed to change the order of output or cause output to not appear at all. Generally optimziations do not alter the observable behavior of a program (with few exceptions not relevant here).


RAII out of the way, lets consider a different example that does trigger the warning (again -Wall -Werror):

#include <iostream>

int fee() {
    std::cout << "hellobye";
    return 42;
};
    
void ber() {
    int f = fee();
    std::cout << " x ";
}

int main() { ber(); }

Output of gcc (https://godbolt.org/z/f47Pcsao5):

<source>: In function 'void ber()':
<source>:9:9: error: unused variable 'f' [-Werror=unused-variable]
    9 |     int f = fee();
      |         ^

It is just a warning, that we can

  • just ignore (https://godbolt.org/z/Mhs8d3qnb)
  • silence via [[maybe_unused]] (https://godbolt.org/z/qM3dK4jbn)
  • fix by simply not declaring a variable (https://godbolt.org/z/693nqffz6)

In any case the output from calling the function must appear.

Regarding the warning, note that generally warnings are not mandated by the standard. Even [[maybe_unused]] is merely a recommendation to compilers. A compiler can ignore the attribute and still be standard conforming.

Imagine the author considered fee a poor name for what the function does in context of ber. They choose to give a much better name f. Imagine further, that they do not want to ignore the warning. Prior to C++17 one had to resort to hacks to silence the warning. With [[maybe_unused]] one has no longer resort to hacks. A future reader does not have to rely on warnings. A variable declared as [[maybe_unsued]] does not need browsing of potentially many lines of code to see that is not used but was given a name on purpose.

发布评论

评论列表(0)

  1. 暂无评论