我正在使用旧版 C API,在该 API 下获取某些资源非常昂贵,释放该资源绝对至关重要。我正在使用 C++14,我想创建一个类来管理这些资源。这是这件事的基本框架...
class Thing
{
private:
void* _legacy;
public:
void Operation1(...);
int Operation2(...);
string Operation3(...);
private:
Thing(void* legacy) :
_legacy(legacy)
{
}
};
这不是真正的单例模式。没有什么是静态的,可能有很多 Thing例如,所有这些都管理着自己的遗留资源。此外,这不仅仅是一个智能指针。包裹指针,_legacy是私有(private)的,所有操作都通过一些对消费者隐藏遗留 API 的公共(public)实例函数公开。
构造函数是私有(private)的,因为 Thing 的实例将从实际获取资源的静态工厂或命名构造函数返回。这是该工厂的廉价仿制品,使用 malloc()作为将调用遗留 API 的代码的占位符 ...
public:
static Thing Acquire()
{
// Do many things to acquire the thing via the legacy API
void* legacy = malloc(16);
// Return a constructed thing
return Thing(legacy);
}
这里是负责释放遗留资源的析构函数,同样,free()只是一个占位符...
~Thing() noexcept
{
if (nullptr != _legacy)
{
// Do many things to free the thing via the legacy API
// (BUT do not throw any exceptions!)
free(_legacy);
_legacy = nullptr;
}
}
现在,我想确保恰好一个遗留资源由恰好一个 Thing 实例管理。 .我不想要 Thing 的消费者类随意传递实例 - 它们必须在本地属于类或函数,直接或通过 unique_ptr , 或者用 shared_ptr 包裹可以传递。为此,我删除了赋值运算符和拷贝构造函数……
private:
Thing(Thing const&) = delete;
void operator=(Thing const&) = delete;
然而,这增加了一个额外的挑战。要么我必须更改我的工厂方法以返回 unique_ptr<Thing>或 shared_ptr<Thing>或者我必须实现 move 语义。我不想规定 Thing 的模式应该使用所以我选择添加一个 move 构造函数和 move 赋值运算符如下...
Thing(Thing&& old) noexcept : _legacy(old._legacy)
{
// Reset the old thing's state to reflect the move
old._legacy = nullptr;
}
Thing& operator= (Thing&& old) noexcept
{
if (&old != this)
{
swap(_legacy, old._legacy);
}
return (*this);
}
完成这一切后,我可以使用 Thing作为一个本地人,把它搬来搬去……
Thing one = Thing::Acquire();
Thing two = move(one);
我无法通过尝试提交 self 分配来打破模式:
Thing one = Thing::Acquire();
one = one; // Build error!
我还可以制作 unique_ptr对一个...
auto three = make_unique<Thing>(Thing::Acquire());
或者一个shared_ptr ...
auto three = make_shared<Thing>(Thing::Acquire());
一切都如我所料,我的析构函数在我所有的测试中都在正确的时刻运行。事实上,唯一令人恼火的是 make_unique和 make_shared两者实际上都调用了 move 构造函数——它并没有像我希望的那样被优化掉。
第一个问题:我是否正确实现了 move 构造函数和 move 赋值运算符? (它们对我来说相当陌生,这将是我第一次在愤怒中使用它们。)
第二个问题:请对此模式发表评论!这是将遗留资源包装在 C++14 类中的好方法吗?
最后:我是否应该更改任何内容以使代码更好、更快、更简单或更具可读性?
最佳答案
您应该将您的 Thing 包装在一个智能指针中,这样您就无需担心复制和 move 语义。
class Thing
{
private:
void* _legacy;
public:
void Operation1(...);
int Operation2(...);
string Operation3(...);
Thing(const Thing&) = delete;
Thing(Thing&&) = delete;
Thing& operator=(const Thing&) = delete;
Thing& operator=(Thing&&) = delete;
static std::shared_ptr<Thing> acquire() {
return std::make_shared<Thing>();
}
private:
Thing() : _legacy(malloc(16)) {
// ...
}
~Thing() {
free(_legacy);
}
};
同样,你可以用unique_ptr来做到这一点:
std::unique_ptr<Thing> acquire() {
return std::make_unique<Thing>();
}
你似乎暗示你只想拥有这个东西的一个实例,尽管即使在你的解决方案中你也没有尝试做那样的事情。为此,您需要静态变量。但请记住,在这种情况下,您的资源只会在您的 main() 函数退出后被释放。例如:
static std::shared_ptr<Thing> acquire() {
static std::shared_ptr<Thing> instance;
if (!instance) {
instance = std::make_shared<Thing>();
}
return instance;
}
或者 unique_ptr 版本:
static Thing& acquire() {
static std::unique_ptr<Thing> instance;
if (!instance) {
instance = std::make_unique<Thing>();
}
return *instance;
}
或者,您可以使用 weak_ptr 在程序范围内获取一个实例,当没有人使用它时,它会被释放。在这种情况下,您将无法为此目的使用 unique_ptr。如果对象被释放然后再次需要,此版本将重新创建对象。
static std::shared_ptr<Thing> acquire() {
static std::weak_ptr<Thing> instance;
if (instance.expired()) {
instance = std::make_shared<Thing>();
}
return instance.lock();
}
关于C++ move 语义 - 包装遗留 C API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32761770/
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“
我使用的是遗留数据库,所以我无法控制数据模型。他们使用了很多多态链接/连接表,就像这样createtableperson(per_ident,name,...)createtableperson_links(per_ident,obj_name,obj_r_ident)createtablereport(rep_ident,name,...)其中obj_name是表名,obj_r_ident是标识符。因此链接的报告将按如下方式插入:insertintoperson(1,...)insertintoreport(1,...)insertintoreport(2,...)insertint
有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=
出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t
我是Ruby和这个网站的新手。下面两个函数是不同的,一个在函数外修改变量,一个不修改。defm1(x)x我想确保我理解正确-当调用m1时,对str的引用被复制并传递给将其视为x的函数。运算符当调用m2时,对str的引用被复制并传递给将其视为x的函数。运算符+创建一个新字符串,赋值x=x+"4"只是将x重定向到新字符串,而原始str变量保持不变。对吧?谢谢 最佳答案 String#+::str+other_str→new_strConcatenation—ReturnsanewStringcontainingother_strconc
我有一个遗留数据库,我正在努力让ActiveRecord使用它。我遇到了连接表的问题。我有以下内容:classTvShow然后我有一个名为tvshowlinkepisode的表,它有2个字段:idShow、idEpisode所以我有2个表和它们之间的连接(多对多关系),但是连接使用非标准外键。我的第一个想法是创建一个名为TvShowEpisodeLink的模型,但没有主键。我的想法是,由于外键是非标准的,我可以使用set_foreign_key并进行一些控制。最后,我想说一些类似TvShow.find(:last).episodes或Episode.find(:last).tv_sho