Первоначально атрибуты с охватом могли переопределять другие атрибуты с тем же названием, если они уже были зарегистрированы к моменту встречи атрибута с охватом. Это позволило использовать некоторые интересные примеры, такие как:
BOOST_LOG_DECLARE_GLOBAL_LOGGER(my_logger, src::logger_mt)
void foo()
{
BOOST_LOG_SCOPED_THREAD_TAG("Section", std::string, "In foo");
BOOST_LOG(get_my_logger()) << "We're in foo section";
}
int main(int, char*[])
{
BOOST_LOG_SCOPED_THREAD_TAG("Section", std::string, "In main");
BOOST_LOG(get_my_logger()) << "We're in main section";
foo();
BOOST_LOG(get_my_logger()) << "We're in main section again";
return 0;
}
Тем не менее, эта функция ввела ряд проблем безопасности, включая проблемы безопасности потоков, которые могут быть трудно отследить. Например, более небезопасно использовать атрибуты в масштабе регистратора на одном и том же регистраторе из разных потоков, поскольку полученный атрибут будет неопределенным:
BOOST_LOG_DECLARE_GLOBAL_LOGGER(my_logger, src::logger_mt)
void thread1()
{
BOOST_LOG_SCOPED_LOGGER_TAG(get_my_logger(), "Tag", std::string, "thread1");
BOOST_LOG(get_my_logger()) << "We're in thread1";
}
void thread2()
{
BOOST_LOG_SCOPED_LOGGER_TAG(get_my_logger(), "Tag", int, 10);
BOOST_LOG(get_my_logger()) << "We're in thread2";
}
int main(int, char*[])
{
BOOST_LOG_SCOPED_LOGGER_TAG(get_my_logger(), "Tag", double, -2.2);
BOOST_LOG(get_my_logger()) << "We're in main";
boost::thread t1(&thread1);
boost::thread t2(&thread2);
t1.join();
t2.join();
BOOST_LOG(get_my_logger()) << "We're in main again";
return 0;
}
Были и другие проблемы, такие как наличие итератора набора атрибутов, который указывает на один объект атрибута, а затем внезапно, не изменяя его, он становится указывающим на другой объект атрибута (возможно, другого типа). Такое поведение может привести к сложным неудачам, которые будет трудно расследовать. Поэтому эта функция в конечном итоге была устранена, что значительно упростило реализацию атрибутов.