- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有一个使用 pimpl
习惯用法的接口(interface),但是该接口(interface)需要是可重入的。然而,调用线程不需要知道锁定。这是一个由四部分组成的问题,其中一部分是无端设计的 C++11 示例(包含示例是为了解决我遇到过的几个类似 FAQ 的问题:locking
、pimpl
、rvalue
和 C++11,其中答案的质量有些可疑)。
在标题中,example.hpp:
#ifndef EXAMPLE_HPP
#define EXAMPLE_HPP
#include <memory>
#include <string>
#ifndef BOOST_THREAD_SHARED_MUTEX_HPP
# include <boost/thread/shared_mutex.hpp>
#endif
namespace stackoverflow {
class Example final {
public:
typedef ::boost::shared_mutex shared_mtx_t;
typedef ::boost::shared_lock< shared_mtx_t > shared_lock_t;
typedef ::boost::unique_lock< shared_mtx_t > unique_lock_t;
Example();
Example(const std::string& initial_foo);
~Example();
Example(const Example&) = delete; // Prevent copying
Example& operator=(const Example&) = delete; // Prevent assignment
// Example getter method that supports rvalues
std::string foo() const;
// Example setter method using perfect forwarding & move semantics. Anything
// that's std::string-like will work as a parameter.
template<typename T>
bool foo_set(T&& new_val);
// Begin foo_set() variants required to deal with C types (e.g. char[],
// char*). The rest of the foo_set() methods here are *NOT* required under
// normal circumstances.
// Setup a specialization for const char[] that simply forwards along a
// std::string. This is preferred over having to explicitly instantiate a
// bunch of const char[N] templates or possibly std::decay a char[] to a
// char* (i.e. using a std::string as a container is a Good Thing(tm)).
//
// Also, without this, it is required to explicitly instantiate the required
// variants of const char[N] someplace. For example, in example.cpp:
//
// template bool Example::foo_set<const char(&)[6]>(char const (&)[6]);
// template bool Example::foo_set<const char(&)[7]>(char const (&)[7]);
// template bool Example::foo_set<const char(&)[8]>(char const (&)[8]);
// ...
//
// Eww. Best to just forward to wrap new_val in a std::string and proxy
// along the call to foo_set<std::string>().
template<std::size_t N>
bool foo_set(const char (&new_val)[N]) { return foo_set(std::string(new_val, N)); }
// Inline function overloads to support null terminated char* && const
// char* arguments. If there's a way to reduce this duplication with
// templates, I'm all ears because I wasn't able to generate a templated
// versions that didn't conflict with foo_set<T&&>().
bool foo_set(char* new_val) { return foo_set(std::string(new_val)); }
bool foo_set(const char* new_val) { return foo_set(std::string(new_val)); }
// End of the foo_set() overloads.
// Example getter method for a POD data type
bool bar(const std::size_t len, char* dst) const;
std::size_t bar_capacity() const;
// Example setter that uses a unique lock to access foo()
bool bar_set(const std::size_t len, const char* src);
// Question #1: I can't find any harm in making Impl public because the
// definition is opaque. Making Impl public, however, greatly helps with
// implementing Example, which does have access to Example::Impl's
// interface. This is also preferre, IMO, over using friend.
class Impl;
private:
mutable shared_mtx_t rw_mtx_;
std::unique_ptr<Impl> impl_;
};
} // namespace stackoverflow
#endif // EXAMPLE_HPP
然后在实现中:
#include "example.hpp"
#include <algorithm>
#include <cstring>
#include <utility>
namespace stackoverflow {
class Example;
class Example::Impl;
#if !defined(_MSC_VER) || _MSC_VER > 1600
// Congratulations!, you're using a compiler that isn't broken
// Explicitly instantiate std::string variants
template bool Example::foo_set<std::string>(std::string&& src);
template bool Example::foo_set<std::string&>(std::string& src);
template bool Example::foo_set<const std::string&>(const std::string& src);
// The following isn't required because of the array Example::foo_set()
// specialization, but I'm leaving it here for reference.
//
// template bool Example::foo_set<const char(&)[7]>(char const (&)[7]);
#else
// MSVC workaround: msvc_rage_hate() isn't ever called, but use it to
// instantiate all of the required templates.
namespace {
void msvc_rage_hate() {
Example e;
const std::string a_const_str("a");
std::string a_str("b");
e.foo_set(a_const_str);
e.foo_set(a_str);
e.foo_set("c");
e.foo_set(std::string("d"));
}
} // anon namespace
#endif // _MSC_VER
// Example Private Implementation
class Example::Impl final {
public:
// ctors && obj boilerplate
Impl();
Impl(const std::string& init_foo);
~Impl() = default;
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
// Use a template because we don't care which Lockable concept or LockType
// is being used, just so long as a lock is held.
template <typename LockType>
bool bar(LockType& lk, std::size_t len, char* dst) const;
template <typename LockType>
std::size_t bar_capacity(LockType& lk) const;
// bar_set() requires a unique lock
bool bar_set(unique_lock_t& lk, const std::size_t len, const char* src);
template <typename LockType>
std::string foo(LockType& lk) const;
template <typename T>
bool foo_set(unique_lock_t& lk, T&& src);
private:
// Example datatype that supports rvalue references
std::string foo_;
// Example POD datatype that doesn't support rvalue
static const std::size_t bar_capacity_ = 16;
char bar_[bar_capacity_ + 1];
};
// Example delegating ctor
Example::Impl::Impl() : Impl("default foo value") {}
Example::Impl::Impl(const std::string& init_foo) : foo_{init_foo} {
std::memset(bar_, 99 /* ASCII 'c' */, bar_capacity_);
bar_[bar_capacity_] = '\0'; // null padding
}
template <typename LockType>
bool
Example::Impl::bar(LockType& lk, const std::size_t len, char* dst) const {
BOOST_ASSERT(lk.owns_lock());
if (len != bar_capacity(lk))
return false;
std::memcpy(dst, bar_, len);
return true;
}
template <typename LockType>
std::size_t
Example::Impl::bar_capacity(LockType& lk) const {
BOOST_ASSERT(lk.owns_lock());
return Impl::bar_capacity_;
}
bool
Example::Impl::bar_set(unique_lock_t &lk, const std::size_t len, const char* src) {
BOOST_ASSERT(lk.owns_lock());
// Return false if len is bigger than bar_capacity or the values are
// identical
if (len > bar_capacity(lk) || foo(lk) == src)
return false;
// Copy src to bar_, a side effect of updating foo_ if they're different
std::memcpy(bar_, src, std::min(len, bar_capacity(lk)));
foo_set(lk, std::string(src, len));
return true;
}
template <typename LockType>
std::string
Example::Impl::foo(LockType& lk) const {
BOOST_ASSERT(lk.owns_lock());
return foo_;
}
template <typename T>
bool
Example::Impl::foo_set(unique_lock_t &lk, T&& src) {
BOOST_ASSERT(lk.owns_lock());
if (foo_ == src) return false;
foo_ = std::move(src);
return true;
}
// Example Public Interface
Example::Example() : impl_(new Impl{}) {}
Example::Example(const std::string& init_foo) : impl_(new Impl{init_foo}) {}
Example::~Example() = default;
bool
Example::bar(const std::size_t len, char* dst) const {
shared_lock_t lk(rw_mtx_);
return impl_->bar(lk, len , dst);
}
std::size_t
Example::bar_capacity() const {
shared_lock_t lk(rw_mtx_);
return impl_->bar_capacity(lk);
}
bool
Example::bar_set(const std::size_t len, const char* src) {
unique_lock_t lk(rw_mtx_);
return impl_->bar_set(lk, len, src);
}
std::string
Example::foo() const {
shared_lock_t lk(rw_mtx_);
return impl_->foo(lk);
}
template<typename T>
bool
Example::foo_set(T&& src) {
unique_lock_t lk(rw_mtx_);
return impl_->foo_set(lk, std::forward<T>(src));
}
} // namespace stackoverflow
我的问题是:
-O4
启用 Link-Time Optimization 时,链接器应该可以绕过 std::unique_ptr
的取消引用开销。有人验证过吗?foo_set("asdf")
并正确链接示例?我们在确定什么是 const char[6]
的正确显式模板实例化时遇到了问题。现在我已经设置了一个模板特化,它创建一个 std::string
对象并代理对 foo_set() 的调用。综合考虑,这似乎是最好的前进方式,但我想知道如何传递“asdf”和 std::decay
结果。关于锁定策略,出于以下几个原因,我对此产生了明显的偏见:
我读过 ACE也使用这种类型的锁定策略,但我欢迎来自 ACE 用户或其他人的一些现实世界的批评:将锁定作为界面的必需部分传递。
为了完整起见,这里有一个 example_main.cpp 供人们咀嚼。
#include <sysexits.h>
#include <cassert>
#include <iostream>
#include <memory>
#include <stdexcept>
#include "example.hpp"
int
main(const int /*argc*/, const char** /*argv*/) {
using std::cout;
using std::endl;
using stackoverflow::Example;
{
Example e;
cout << "Example's foo w/ empty ctor arg: " << e.foo() << endl;
}
{
Example e("foo");
cout << "Example's foo w/ ctor arg: " << e.foo() << endl;
}
try {
Example e;
{ // Test assignment from std::string
std::string str("cccccccc");
e.foo_set(str);
assert(e.foo() == "cccccccc"); // Value is the same
assert(str.empty()); // Stole the contents of a_str
}
{ // Test assignment from a const std::string
const std::string const_str("bbbbbbb");
e.foo_set(const_str);
assert(const_str == "bbbbbbb"); // Value is the same
assert(const_str.c_str() != e.foo().c_str()); // Made a copy
}
{
// Test a const char[7] and a temporary std::string
e.foo_set("foobar");
e.foo_set(std::string("ddddd"));
}
{ // Test char[7]
char buf[7] = {"foobar"};
e.foo_set(buf);
assert(e.foo() == "foobar");
}
{ //// And a *char[] & const *char[]
// Use unique_ptr to automatically free buf
std::unique_ptr<char[]> buf(new char[7]);
std::memcpy(buf.get(), "foobar", 6);
buf[6] = '\0';
e.foo_set(buf.get());
const char* const_ptr = buf.get();
e.foo_set(const_ptr);
assert(e.foo() == "foobar");
}
cout << "Example's bar capacity: " << e.bar_capacity() << endl;
const std::size_t len = e.bar_capacity();
std::unique_ptr<char[]> buf(new char[len +1]);
// Copy bar in to buf
if (!e.bar(len, buf.get()))
throw std::runtime_error("Unable to get bar");
buf[len] = '\0'; // Null terminate the C string
cout << endl << "foo and bar (a.k.a.) have different values:" << endl;
cout << "Example's foo value: " << e.foo() << endl;
cout << "Example's bar value: " << buf.get() << endl;
// Set bar, which has a side effect of calling foo_set()
buf[0] = 'c'; buf[1] = buf[2] = '+'; buf[3] = '\0';
if (!e.bar_set(sizeof("c++") - 1, buf.get()))
throw std::runtime_error("Unable to set bar");
cout << endl << "foo and bar now have identical values but only one lock was acquired when setting:" << endl;
cout << "Example's foo value: " << e.foo() << endl;
cout << "Example's bar value: " << buf.get() << endl;
} catch (...) {
return EX_SOFTWARE;
}
return EX_OK;
}
并构建使用 C++11
和 libc++
的说明:
clang++ -O4 -std=c++11 -stdlib=libc++ -I/path/to/boost/include -o example.cpp.o -c example.cpp
clang++ -O4 -std=c++11 -stdlib=libc++ -I/path/to/boost/include -o example_main.cpp.o -c example_main.cpp
clang++ -O4 -stdlib=libc++ -o example example.cpp.o example_main.cpp.o /path/to/boost/lib/libboost_exception-mt.dylib /path/to/boost/lib/libboost_system-mt.dylib /path/to/boost/lib/libboost_thread-mt.dylib
作为一个小小的奖励,我更新了这个例子,在 foo_set()
方法中包含了使用右值引用的完美转发。虽然不完美,但它比我预期的要花费更长的时间来正确地进行模板实例化,这是链接时的一个问题。这还包括 C 基本类型的适当重载,包括:char*
、const char*
、char[N]
和 const char[N]
.
最佳答案
对于问题 1,我想做的一件事是使用 SFINAE 限制传入的锁类型作为 LockType
允许 shared_lock_t
或 unique_lock_t
。
即:
template <typename LockType>
typename std::enable_if<
std::is_same< LockType, shared_lock_t > || std::is_same< LockType, unique_lock_t >,
size_t
>::type
bar_capacity(LockType& lk) const;
...但这确实有点冗长。
这意味着传入错误类型的 Lock 会给您一个“不匹配”的错误。另一种方法是有两个不同的 bar_capacity
,它们采用 shared_lock_t
和 unique_lock_t
暴露,以及一个私有(private)的 bar_capacity,它们采用模板 锁定类型
。
如所写,任何具有 .owns_lock()
方法并返回可转换为 bool
的类型的类型都是有效参数...
关于C++11 可重入类锁定策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13240015/
作者:小林coding 计算机八股文网站:https://xiaolincoding.com 大家好,我是小林。 今天跟大家聊聊,常见的缓存更新策略。 Cache Aside(旁路缓存)策略; Rea
我使用 git 多年,最近为了一个项目改用 mercurial。在过去的 6 个月里,我已经学会了如何通过命令行很好地使用 Mercurial。 这可能是我的想象,但在我看来,mercurial 在
这个问题适合任何熟悉的人 Node.js express Passport 带有 Passport 的 JWT 身份验证(JSON Web token ) Facebook OAuth2.0 或谷歌
在 Coq 中,当试图证明记录的相等性时,是否有一种策略可以将其分解为所有字段的相等性?例如, Record R := {x:nat;y:nat}. Variables a b c d : nat.
我正在处理的项目目前只有一个 Bootstrap 文件,用于初始化应用程序中的所有 javascript 对象。类似于下面的代码 if(document.getElementById('nav'))
我正在考虑使用 OpenLDAP 在首次登录时添加密码到期和强制更改密码。 似乎使用 ppolicy 覆盖来实现这一点。 当我在 ppolicy.schema 中看到这个时,我开始使用 ppolicy
这基本上是我昨天问的一个问题的重新陈述,因为我得到的一个答案似乎没有理解我的问题,所以我一定是不清楚。我的错。 因为 WPF 依赖于 DirectX,所以它对卡和驱动程序的内部非常敏感。我有一个案例,
我是单点登录(SSO)概念的新手。我开始知道 SAML 请求和响应是实现 SSO 流程的最佳方式。然后我开始阅读有关 SAML2.0 的信息。我来了一个术语 NameIdPolicy 在 saml1.
关闭。这个问题需要更多 focused .它目前不接受答案。 想改进这个问题?更新问题,使其仅关注一个问题 editing this post . 5年前关闭。 Improve this questi
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 9 年前。 Improv
在 Azure 上创建新的 SQL 数据库时,它将“计算+存储”选项设置为“2 vCore + 32GB 数据最大大小”作为默认配置,但我不想使用 vCore,我可以更改它。但问题是,是否可以通过策略
我希望创建一项策略,防止在未启用身份验证的情况下创建应用服务(仅审核它们是不够的)。 以下策略可以正确识别未启用身份验证的现有资源: { "mode": "All", "policyRule"
我正在尝试从现有 AuditIfNotExists 策略创建 DeployIfNotExists 策略。部署时不会出错,但会错误提示“没有相关资源与策略定义中的效果详细信息匹配”。当评估政策时。当我将
我正在尝试从现有 AuditIfNotExists 策略创建 DeployIfNotExists 策略。部署时不会出错,但会错误提示“没有相关资源与策略定义中的效果详细信息匹配”。当评估政策时。当我将
我正在使用 wunderground 的 json api 来查询我网站上的天气状况。 api 为我提供了一个包含所有必要数据的漂亮 json 对象,但我每天只能进行多次调用。存储这些数据的首选方式是
我有一个名为可视化数据结构的项目。我有这样的 OOP 设计。 Class VisualDataStructures extends JFrame Class ControlPanel extends
这个问题在这里已经有了答案: 关闭 14 年前。 副本: Use javascript to inject script references as needed? Javascript 没有任何指
Android 应用程序遇到了一些 ANR 问题,因此我实现了 StrictMode 策略。以前从未使用过这个,所以希望有人可以帮助解释以下内容: 为什么日志显示 2 个看似相似的违规行为,除了前 4
我目前正在尝试解决一个问题。假设我们在路上行驶,我们知道路上有 10 家酒店。每家酒店都有 0 到 6 星。我的问题是:找到选择星级酒店的最佳解决方案。唯一的问题是:您不能回头去参观您已经决定不去的酒
我正在将我的应用程序迁移到 MVP。从这个 konmik 中获得了有关静态演示者模式的提示 这是我的简要 MVP 策略。为简洁起见,删除了大部分样板和 MVP 监听器。这个策略帮助我改变了方向,证明了
我是一名优秀的程序员,十分优秀!