我们目前存储了几个不同的数据模型集合,如下所示:
std::map<std::string, std::map<int64_t, std::shared_ptr<DataObject>>> models;
字符串映射到一个已知的类型列表,这都是通过序列化处理的。嵌套映射包含“对象 ID”和关联(反序列化)std::shared_ptr 的集合
DataObject 是一个基类,我们从中派生出多种类型。 我们有一个方法来获取给定类型的所有数据对象: 这只是在给定的“类型”键处返回指向 map 的指针。 今天我遇到了一个代码审查来添加我认为调用 UB 但似乎起作用的以下内容。这让我有点紧张并寻找有效的解决方案: 像这样转换的好处是它不涉及循环或复制(据我所知),它是一个简单的指针转换。这太妙了。但我认为它既不便携也不安全,尽管我不知道最好的便携和安全替代品是什么。 我在下面有一个玩具版本的简化版本,它确实按预期吐出正确的输出: 我的问题是是否有一种不涉及大量复制的好方法,或者至少是否有一种干净的方法来做到这一点。我们目前正在使用 C++17。static std::map<int64_t, std::shared_ptr<DataObject>> *getAll(std::string type);
template <typename M>
static std::map<int64_t, std::shared_ptr<M>> *getAll(const std::string &type) {
auto castObjectMap = reinterpret_cast<std::map<int64_t, std::shared_ptr<M>>*>(getAll(type));
return castObjectMap;
}
#include <iostream>
#include <memory>
#include <string>
#include <map>
using namespace std;
struct Base {
Base(){}
virtual ~Base(){}
Base(int u):x(u){}
int x = 0;
};
struct Derived : public Base {
Derived(){}
Derived(int u, int v):Base(u),y(v){}
int y = 0;
};
int main() {
map<int, shared_ptr<Base>> test {
{0, make_shared<Derived>(2, 3)},
{1, make_shared<Derived>(4, 5)},
{2, make_shared<Derived>(6, 7)}
};
map<int, shared_ptr<Derived>> *castVersion = reinterpret_cast<map<int, shared_ptr<Derived>>*>(&test);
for(auto&&kv : *castVersion){
cout << kv.first << ": " << kv.second->x << ", " << kv.second->y << std::endl;
}
return 0;
}
最佳答案
它不会提供完全相同的界面,但想到的一个类似但更安全的想法是使用 boost::transform_iterator 创建透明处理转换 shared_ptr 的迭代器 map 内的指针。
#include <memory>
#include <utility>
#include <type_traits>
#include <boost/iterator/transform_iterator.hpp>
template <class Derived, class Iterator>
class downcast_pair_iterator
: public boost::transform_iterator<
std::pair<
typename std::iterator_traits<Iterator>::value_type::first_type,
const std::shared_ptr<Derived>
> (*)(Iterator),
Iterator>
{
public:
using base_value_type = typename std::iterator_traits<Iterator>::value_type;
using key_type = const typename base_value_type::first_type;
using base_mapped_type = typename base_value_type::second_type;
using mapped_type = const std::shared_ptr<Derived>;
using value_type = std::pair<key_type, mapped_type>;
private:
template <typename T>
static T* shared_to_raw(const std::shared_ptr<T>&); // undefined
static_assert(std::is_base_of_v<
std::remove_pointer_t<
decltype(shared_to_raw(std::declval<base_mapped_type&>()))>,
Derived>);
static value_type convert(const base_value_type& pair_in)
{
return value_type(pair_in.first,
std::static_pointer_cast<Derived>(pair_in.second));
}
public:
explicit downcast_pair_iterator(Iterator iter)
: transform_iterator(iter, &convert) {}
};
template <class Derived, class Iterator>
auto make_downcast_pair_iter(Iterator iter)
{
return downcast_pair_iterator<Derived, Iterator>(iter);
}
template <class Derived, class Range>
class downcast_pair_range
{
public:
explicit downcast_pair_range(Range& c)
: source_ref(c) {}
auto begin() const {
using std::begin;
return make_downcast_pair_iter<Derived>(begin(source_ref));
}
auto end() const {
using std::end;
return make_downcast_pair_iter<Derived>(end(source_ref));
}
private:
Range& source_ref;
};
template <class Derived, class Range>
auto make_downcast_pair_range(Range& r)
{
return downcast_pair_range<Derived, Range>(r);
}
template <class Derived, class Range>
auto make_downcast_pair_range(const Range &r)
{
return downcast_pair_range<Derived, const Range>(r);
}
那么你的例子main可能会变成:
int main() {
std::map<int, std::shared_ptr<Base>> test {
{0, std::make_shared<Derived>(2, 3)},
{1, std::make_shared<Derived>(4, 5)},
{2, std::make_shared<Derived>(6, 7)}
};
for (auto&& kv : make_downcast_pair_range<Derived>(test)){
std::cout << kv.first << ": "
<< kv.second->x << ", " << kv.second->y << std::endl;
}
return 0;
}
这避免了创建任何第二个容器对象,并且在正确使用时不涉及未定义的行为。使用转换迭代器将主要产生与不安全转换相同的机器代码,除了取消引用确实创建了一个新的 shared_ptr<Derived>。对象,这将涉及一点引用计数开销。 See the full working program on coliru.
除了使用make_downcast_pair_range<Derived>(some_map)如基于范围的 for 所示以上,make_downcast_pair_iterator<Derived>可以直接用于获取用于其他目的的转换迭代器,例如来自 map 的 find(k) 的结果。 .给定一个转换迭代器,您可以使用 iter.base() 返回到真实 map 的迭代器,例如传递给 map 的 erase(iter) .
当然,使用 std::static_pointer_cast 的结果如果指针实际上没有指向 Derived,仍然是未定义的行为对象。如果担心有人在获取对象时可能会使用错误的“派生”模板参数,或者映射可能以某种方式最终包含指向错误派生对象类型的指针,您可以更改 downcast_pair_iterator<D, I>::convert要使用的私有(private)函数 std::dynamic_pointer_cast相反,如果结果是空指针,则抛出或中止。
关于c++ - 将 std::map<int, std::shared_ptr<Base>> 转换为 std::map<int, std::shared_ptr<Derived>> 的最有效安全方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57384254/
这似乎应该有一个直截了当的答案,但在Google上花了很多时间,所以我找不到它。这可能是缺少正确关键字的情况。在我的RoR应用程序中,我有几个模型共享一种特定类型的字符串属性,该属性具有特殊验证和其他功能。我能想到的最接近的类似示例是表示URL的字符串。这会导致模型中出现大量重复(甚至单元测试中会出现更多重复),但我不确定如何让它更DRY。我能想到几个可能的方向...按照“validates_url_format_of”插件,但这只会让验证干给这个特殊的字符串它自己的模型,但这看起来很像重溶液为这个特殊的字符串创建一个ruby类,但是我如何得到ActiveRecord关联这个类模型
我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request
这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][
我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll
我正在使用RubyonRails3.2.2,我想从我的模型/类中“提取”一些方法。也就是说,在不止一个类/模型中,我有一些方法(注意:方法与用户授权相关,并被命名为“CRUD方式”),这些方法实际上是相同的;所以我认为DRY方法是将这些方法放在“共享”模块或类似的东西中。实现该目标的常见且正确的方法是什么?例如,我应该将“共享”代码放在哪里(在哪些目录和文件中)?如何在我的类/模型中包含提到的方法?你有什么建议?注意:我正在寻找“RubyonRails制作东西的方式”。 最佳答案 一种流行的方法是使用ActiveSupport关注点
如何将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.你能做的最好的事情是:
是否可以在PyYAML或Ruby的Psych引擎中禁用创建anchor和引用(并有效地显式列出冗余数据)?也许我在网上搜索时遗漏了一些东西,但在Psych中似乎没有太多可用的选项,而且我也无法确定PyYAML是否允许这样做.基本原理是我必须序列化一些数据并将其以可读的形式传递给一个不是真正的技术同事进行手动验证。有些数据是多余的,但我需要以最明确的方式列出它们以提高可读性(anchor和引用是提高效率的好概念,但不是人类可读性)。Ruby和Python是我选择的工具,但如果有其他一些相当简单的方法来“展开”YAML文档,它可能就可以了。 最佳答案