如何在下面的示例中检测未定义的行为?
var todoApp = (function(){
var todo = [];
//cacheDOM
var $el = $('#app');
var $input = $el.find('input');
var $button = $el.find('button');
var $ul = $el.find('ul');
var listItem = $el.find('#todo-item').html();
var $del = $el.find('.del')
// bindEvents
$button.on('click', addTodo);
$ul.on('click', '.del', deleteTodo);
$ul.on('mouseenter mouseleave', '.del', hoverChange);
//render call
render();
//function declarations
function onHoverChange(e){
var $elem = $(e.target).closest('li');
$elem.toggleClass('delete');
}
function addTodo(e){
var $elem = $(e.target).closest('li');
todo.push($input.val());
$input.val('');
render();
}
function deleteTodo(e){
var $elem = $(e.target).closest('li');
var $rem = $ul.find('li').index($elem);
todo.splice($rem, 1);
render();
}
function render(){
var data = {
todo: todo
}
$ul.html(Mustache.to_html(listItem, data));
}
})();
使用#include <iostream>
#include <stream>
int main() {
std::cout << "Undefined: " << std::string().front() << std::endl;
return 0;
}
编译。
我在编译时或运行时的预期输出都是错误的。根据{{3}},对空字符串调用clang++ -fsanitize=address,undefined -g -Wall -Wextra main.cc
是未定义的行为。 实际输出为front()
。
Undefined:
答案 0 :(得分:1)
将Baum mit Augen的链接转换为答案。
使用GCC编译时添加标志-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC
。同样不适用于Clang。
这样可以在std::basic_string
内启用运行时检查。
结果(为清晰起见,添加了换行符):
$ /usr/local/Cellar/gcc/7.2.0/bin/g++-7 main.cc -g -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC
$ ./a.out
Undefined:
/usr/local/Cellar/gcc/7.2.0/include/c++/7.2.0/bits/basic_string.h:1077:
std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::reference
std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::front()
[with _CharT = char; _Traits = std::char_traits<char>;
_Alloc = std::allocator<char>;
std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::reference = char&]:
Assertion '!empty()' failed.
[1] 24143 abort ./a.out
答案 1 :(得分:1)
使用标准容器并不总是可以进行编译时警告,但实现自由函数将允许额外的检查,可以选择使用编译器标志关闭。
#define NDEBUG
#include <iostream>
#include <string>
#include <cassert>
#include <stdexcept>
struct assert_on_failure
{
template<class ErrorMessage>
void check(bool condition, ErrorMessage&& msg) const
{
if (!condition)
assert(!msg);
}
};
struct throw_on_failure
{
template<class ErrorMessage>
void check(bool condition, ErrorMessage&& msg) const
{
if (!condition)
throw std::runtime_error(msg);
}
};
#ifdef NDEBUG
constexpr auto default_failure_policy = throw_on_failure{};
#else
constexpr auto default_failure_policy = assert_on_failure{};
#endif
template
<
class Container,
class FailurePolicy = std::add_lvalue_reference_t<decltype(default_failure_policy)>
>
decltype(auto) get_front(Container&& cont,
FailurePolicy&& policy = default_failure_policy)
{
policy.check(cont.size() > 0, "container is empty");
return cont.front();
}
int main() {
std::cout << "Undefined: " << get_front(std::string()) << std::endl;
return 0;
}