避免在没有原始指针的情况下复制映射的键

发布于 2024-10-16 06:51:50 字数 1047 浏览 4 评论 0原文

每次在键为 std::string 的 std::map 中插入一对时,它都会生成两个副本。您可以避免使用原始指针,但它是异常不安全的。有没有办法使用智能指针而不是原始指针?

示例代码:

// To compile: g++ -std=c++0x exmaple.cpp -o example 

#include <iostream>
#include <string>
#include <map>
#include <memory>

class StringSquealer: public std::string
{
  public:
    StringSquealer(const std::string s) : std::string(s) {}
    StringSquealer(const StringSquealer&) 
    { 
      std::cout << "COPY-CONSTRUCTOR" << std::endl; 
    }
};

int main()
{
  // Inefficient
  std::map<StringSquealer,int> m1;
  m1[StringSquealer("key")] = 1;
  std::cout << "---" << std::endl;

  // Exception-unsafe
  std::map<StringSquealer*,int> m2;
  m2[new StringSquealer("key")] = 1;

  //Ideal??
  std::map<std::unique_ptr<StringSquealer>,int> m3;
  std::unique_ptr<StringSquealer> s(new StringSquealer("key"));
  //!m3[std::move(s)] = 1;  // No compile
}

输出:

COPY-CONSTRUCTOR
COPY-CONSTRUCTOR
---

Every time you insert a pair in a std::map whose key is a std::string, it makes two copies. You can avoid using raw pointers but it is exception-unsafe. Is there some way to use a smart pointer instead of a raw pointer?

Example code:

// To compile: g++ -std=c++0x exmaple.cpp -o example 

#include <iostream>
#include <string>
#include <map>
#include <memory>

class StringSquealer: public std::string
{
  public:
    StringSquealer(const std::string s) : std::string(s) {}
    StringSquealer(const StringSquealer&) 
    { 
      std::cout << "COPY-CONSTRUCTOR" << std::endl; 
    }
};

int main()
{
  // Inefficient
  std::map<StringSquealer,int> m1;
  m1[StringSquealer("key")] = 1;
  std::cout << "---" << std::endl;

  // Exception-unsafe
  std::map<StringSquealer*,int> m2;
  m2[new StringSquealer("key")] = 1;

  //Ideal??
  std::map<std::unique_ptr<StringSquealer>,int> m3;
  std::unique_ptr<StringSquealer> s(new StringSquealer("key"));
  //!m3[std::move(s)] = 1;  // No compile
}

Output:

COPY-CONSTRUCTOR
COPY-CONSTRUCTOR
---

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

请持续率性 2024-10-23 06:51:50

这是低效的,因为你的类写错了。 C++0x 提供右值引用 - 您刚刚编写了类,因此它无法利用它们。

class StringSquealer: public std::string
{
  public:
    StringSquealer(std::string&& s) : std::string(std::move(s)) {}
    StringSquealer(const std::string& s) : std::string(s) {}
    StringSquealer(const StringSquealer& s)
        : std::string(s) 
    { 
      std::cout << "COPY-CONSTRUCTOR" << std::endl; 
    }
    StringSquealer(StringSquealer&& s)
        : std::string(std::move(s)) 
    {
        std::cout << "MOVE-CONSTRUCTOR" << std::endl;
    }
};

并将 unique_ptr 作为键?那是不可能的。您永远无法取回相同的 unique_ptr - 即使您以某种方式获得相同的指针并从中构造一个 unique_ptr,您也会删除该指针比较完成后立即按键。

It's inefficient because you wrote your class wrong. C++0x provides rvalue references- you just wrote your class so that it couldn't take advantage of them.

class StringSquealer: public std::string
{
  public:
    StringSquealer(std::string&& s) : std::string(std::move(s)) {}
    StringSquealer(const std::string& s) : std::string(s) {}
    StringSquealer(const StringSquealer& s)
        : std::string(s) 
    { 
      std::cout << "COPY-CONSTRUCTOR" << std::endl; 
    }
    StringSquealer(StringSquealer&& s)
        : std::string(std::move(s)) 
    {
        std::cout << "MOVE-CONSTRUCTOR" << std::endl;
    }
};

And unique_ptr as a key? That's impossible. You could never get back the same unique_ptr- even if you got the same pointer somehow and constructed a unique_ptr from it, you'd delete the key as soon as the comparison was done.

酒与心事 2024-10-23 06:51:50

在我详细介绍之前,请确保不要进行任何类型的优化,除非您确定制作副本的成本太大以至于您需要解决它。使用字符串作为键很好而且直观,但避免它所需的代码有点麻烦。

使用 unique_ptr 作为映射中的键确实可以工作,但我真的不认为这是一个好主意。这意味着为了查询映射中的键,您必须将用作键的字符串存储为 unique_ptr。这意味着除非您将所有字符串存储为 unique_ptrs,否则您需要为要查找的每个字符串创建一个副本。由于插入往往比查找少见得多,因此这似乎以牺牲常见情况为代价来优化不常见情况。我强烈劝阻你不要这样做。

如果您确实想摆脱不必要的复制,您可能需要考虑选择执行写入时复制的字符串实现。这样,制作字符串副本的成本为 O(1),并且在插入期间制作的两个副本将很便宜。这可能需要您在其他地方使用此字符串实现,并且必须小心多线程问题,但如果您愿意,它可以工作。

Before I go into any further detail, please be sure not to do any sort of optimizations like these uless you're sure that the cost of making the copies is so large that you need to address it. Having strings as keys is fine and intuitive, and the code required to avoid it is a bit hairy.

Using a unique_ptr as a key in the map can indeed be made to work, but I really don't think it's a good idea. This would mean that in order to query a key in the map, you would have to have the string to use as a key stored as a unique_ptr. This means that unless you're storing all of your strings as unique_ptrs, you would need to make a copy of each string that you wanted to look up. Since insertions tend to be much less common than lookups, this seems to optimize the uncommon case at the expense of the common one. I'd strongly discourage you from doing this.

If you do want to get rid of copying unnecessarily, you might want to instead consider picking an implementation of a string that does copy-on-write. That way, the cost of making a copy of the string is O(1) and the two copies being made during insertion will be cheap. This would probably require you to use this string implementation elsewhere and to have to be careful about multithreading issues, but it could be made to work if you wanted.

携余温的黄昏 2024-10-23 06:51:50

这里有几个错误:

  • 您不应该从 std::string 派生类
  • 您不应该使用 unique_ptr 作为映射中的键

您可以使用shared_ptr 作为键,然后您需要一个比较类来比较共享指针。

但是,您最好只使用 std::string 作为键,除非它们是非常长的字符串,以至于复制它们的成本很高。

顺便说一句,复制中最昂贵的部分可能是分配而不是复制本身。为此,您可以考虑将 basic_string 与自定义分配器一起使用。

Several things wrong here:

  • You should not derive classes from std::string
  • You should not use unique_ptr as a key in a map

You can use shared_ptr as the key and then you would need a comparison class to compare the shared-pointers.

However you would be better off just using std::string as the key unless they are very long strings such that copying them is expensive.

By the way, the most expensive part of the copying is likely to be the allocation rather than the copying itself. For that you could consider using basic_string with a custom allocator.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文