从reddit/hackernews/lobsters/meetingcpp知乎等等摘抄一些c++动态
周刊项目地址|在线地址 |知乎专栏 | 腾讯云+社区 |
欢迎投稿,推荐或自荐文章/软件/资源等
可以贴在下一期草稿里 草稿链接
2022 0916
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 2022-09-14 第167期
cppcon 2022还在进行中。视频放了几个。没看。有参与者说今年不太行。我去年还没怎么看。看视频信息量太低了。得看PPT然后找视频看。最近没啥空。周末有时间可以看看
打印堆栈支持。看代码
#include <stacktrace>
#include <iostream>
int foo() {
std::cout << std::stacktrace::current();
return {};
}
int main() {
return foo();
}
可算支持了
各个编译器Modules支持的状态进展介绍
标准库的std::optional是不支持T&和void的。作者说了下自己可能会用到这个场景,标准库应该加上
之前介绍过。介绍了谷歌浏览器团队在解决指针问题的一些实践。实现了很多,但是有些文档不可见。
也介绍了其他方案的实现,比如这个unowned_ptr
代码难找就没有深入研究。不过讨论还是值得一看的。我后面整理一下
介绍Sanitizer
seastar代码走读
注意co_await的阻塞语义,永远超时导致不能使用
四舍五入等于c的东西。可以看个热闹
各种容器介绍,比如folly::fbvector, boost::small_vector等等。感兴趣的可以看看
写了个工具验证gcc产出的代码对不对,具体就是验证gimple IR。我不太懂。感兴趣可以看看
office团队要用module,这是msvc团队的一些探索
介绍msvc调试的。没用过不了解,有没有懂的给讲讲
代码长这样
struct WidgetTracker : IWidgetChangeNotificationSink
{
/* other stuff not relevant here */
/// IWidgetChangeNotificationSink
STDMETHODIMP OnCurrentWidgetChanged();
private:
WRL::ComPtr<IWidget> m_currentWidget;
std::mutex m_mutex;
};
HRESULT WidgetTracker::OnCurrentWidgetChanged()
{
auto guard = std::lock_guard(m_mutex);
RETURN_IF_FAILED(GetCurrentWidget(&m_currentWidget));
return S_OK;
}
OnCurrentWidgetChanged是个回调,如果m_currentWidget变了就会被调用
问题在于OnCurrentWidgetChanged被调用这个m_mutex锁住的瞬间,m_currentWidget析构,结果又触发一次OnCurrentWidgetChanged,导致死锁
这个问题根源在于锁锁不住comptr,无法避免递归调用。
解决方法也很简单,拷贝一份对象就行了。
HRESULT WidgetTracker::OnCurrentWidgetChanged()
{
WRL::ComPtr<IWidget> widget; // 可能别人在用它
auto guard = std::lock_guard(m_mutex);
RETURN_IF_FAILED(GetCurrentWidget(&widget));
m_currentWidget.Swap(widget);
return S_OK;
}
作者之前讨论过一段类似的代码,用的,shared_ptr, 也有相同的问题
class ThingManager
{
private:
std::mutex things_lock_;
std::vector<std::shared_ptr<Thing>> things_;
public:
void AddThing(std::shared_ptr<Thing> thing)
{
std::lock_guard guard(things_lock_);
things_.push_back(std::move(thing));
}
void RemoveThingById(int32_t id)
{
std::lock_guard guard(things_lock_);
auto it = std::find_if(things_.begin(), things_.end(),
[&](auto&& thing)
{
return thing->id() == id;
});
if (it != things_.end()) {
things_.erase(it);
}
}
};
class SuperThing : Thing
{
private:
ThingManager& manager_;
int32_t helper_id_ = 0;
public:
SuperThing(ThingManager& manager) :
manager_(manager)
{
auto helper = std::make_shared<Thing>();
helper_id_ = helper->id();
manager_.AddThing(helper);
}
~SuperThing()
{
manager_.RemoveThingById(helper_id_);
}
};
void test(ThingManager& manager)
{
auto s = std::make_shared<SuperThing>(manager);
auto id = s->id();
manager.AddThing(s);
s = nullptr; // 1
manager.RemoveThingById(id); // 2
}
问题是相同的,同一个锁被锁两次。如何触发?首先SuperThing会在2 这行真正的析构,1那行只会引用计数-1
RemoveThingById(id)是会锁的,内部触发了SuperThing析构,然后又调用了manager_.RemoveThingById(helper_id_);
,锁了同一个锁
你可能觉得这种代码写的有问题。这是锁和shared_ptr和坑爹析构三个同时引入引发的问题,我遇不到
解决方法也很简单。让这个shared_ptr活着,因为不知道哪个外部调用会用到这个shared_ptr
void RemoveThingById(int32_t id)
{
std::shared_ptr removed_thing; // 求求你活着
{
std::lock_guard guard(things_lock_);
auto it = std::find_if(things_.begin(), things_.end(), ...);
if (it != things_.end()) {
removed_thing = *it;
things_.erase(it);
}
}
}
引用计数指针和锁的问题。这里打个问号。要注意
oldnewthing的博客真精彩,总能遇到各种莫名其妙的bug
标准库提供了新函数来更友好的判断整数大小,不用自己写那些符号转换逻辑了
比如
template <class _Ty1, class _Ty2>
_NODISCARD constexpr bool cmp_equal(const _Ty1 _Left, const _Ty2 _Right) noexcept {
static_assert(_Is_standard_integer<_Ty1> && _Is_standard_integer<_Ty2>,
"The integer comparison functions only "
"accept standard and extended integer types.");
if constexpr (is_signed_v<_Ty1> == is_signed_v<_Ty2>) {
return _Left == _Right;
} else if constexpr (is_signed_v<_Ty2>) {
return _Left == static_cast<make_unsigned_t<_Ty2>>(_Right) && _Right >= 0;
} else {
return static_cast<make_unsigned_t<_Ty1>>(_Left) == _Right && _Left >= 0;
}
}
VPSUBUSB z, x, y
VPMINUB z, x, y
VPCMPEQB w, z, x
我不太懂。不评价
用avx处理字符串中的斜杠,比如my title is \"La vie\"
通常写法
for (...) {
if ((*in == '\\') || (*in == '"')) {
*out++ = '\\';
}
*out++ = *in;
}
sse/avx写法
__m512i solidus = _mm512_set1_epi8('\\');
__m512i quote = _mm512_set1_epi8('"');
for (; in + 32 <= finalin; in += 32) {
__m256i input = _mm256_loadu_si256(in);
__m512i input1 = _mm512_cvtepu8_epi16(input);
__mmask64 is_solidus = _mm512_cmpeq_epi8_mask(input1, solidus);
__mmask64 is_quote = _mm512_cmpeq_epi8_mask(input1, quote);
__mmask64 is_quote_or_solidus = _kor_mask64(is_solidus, is_quote);
__mmask64 to_keep = _kor_mask64(is_quote_or_solidus, 0xaaaaaaaaaaaaaaaa);
__m512i shifted_input1 = _mm512_bslli_epi128(input1, 1);
__m512i escaped =
_mm512_mask_blend_epi8(is_quote_or_solidus, shifted_input1, solidus);
_mm512_mask_compressstoreu_epi8(out, to_keep, escaped);
out += _mm_popcnt_u64(_cvtmask64_u64(to_keep));
}
给我看困了
这里有个类似的https://branchfree.org/2019/03/06/code-fragment-finding-quote-pairs-with-carry-less-multiply-pclmulqdq/
这段代码有bug,不懂这几个API的可能看不懂
bool ShuttingDown = false;
void MainThread()
{
DWORD id;
auto hThread = CreateThread(nullptr, 0, WorkerThread,
nullptr, 0, &id); // succeeds
BlahBlahBlah(); // do useful work
// Time to clean up. Post an APC to the worker thread
// to tell it that it's time to go home.
QueueUserAPC(WakeWorker, hThread, 0); // succeeds
WaitForSingleObject(hThread, INFINITE); // hangs
CloseHandle(hThread);
}
void CALLBACK WakeWorker(ULONG_PTR)
{
ShuttingDown = true;
}
DWORD CALLBACK WorkerThread(void*)
{
// Do work until shut down.
do
{
// All work is posted via APCs.
SleepEx(INFINITE, TRUE);
} while (!ShuttingDown);
return 0;
}
简单来说SleepEx通过QueueUserAPC来唤醒,有一种场景,QueueUserAPC唤醒了,但是CreateThread执行的慢,导致SleepEx没收到通知,从而永远死锁
怎么解决这个问题?把do while循环改成while就行了。因为这种场景已经shutdown了,不应该执行sleep
DWORD CALLBACK WorkerThread(void*)
{
// Do work until shut down.
while (!ShuttingDown)
{
// All work is posted via APCs.
SleepEx(INFINITE, TRUE);
}
return 0;
}
讲协程的。说来惭愧我还不是很懂。就不介绍了
简单来说只有clang编译器支持std::format