gpt4 book ai didi

c++ - 内存管理的正确方式

转载 作者:行者123 更新时间:2023-11-30 02:27:49 26 4
gpt4 key购买 nike

class Word
{
private:
std::string w;
public:
Word(std::string w) : w(w) {}
};

class Sentence
{
private:
std::list<Word *> words;

public:
Sentence(std::list<Word *> words) : words(words) {}

~Sentence() {
for (auto word : words)
delete word;
words.clear();
}
};

int main() {
Word *word1 = new Word("abc");
Word *word2 = new Word("def");
Sentence sentence1( std::list<Word *>({word1, word2}) );
Sentence sentence2 = sentence1;
return 0;
}

(实际类更大;我确实需要使用指向 Word 的指针,在其他函数中分配)对象 word1word2 将被删除两次。我有这些解决问题的选择:

  1. 添加方法 Word * Word::clone(const Word *word)Sentence * Sentence::clone(const Sentence *s) 并在 中调用它们>Sence::operator=。但是在这种情况下,我的程序使用了过多的内存(句子中的单词是相同的,但在内存中分配了两次)。
  2. 使用智能指针。然后我的程序变得有点低效(并且代码变得更复杂)。
  3. bool isCopy 添加到Sentence 并仅在isCopy == false 时删除单词。我认为这看起来很愚蠢。

那么我应该怎么做更好呢?

最佳答案

永远不要使用指向任何东西的指针集合。如果您必须有 word 的堆分配实现,请将其包装在具有类似值行为的句柄类中。

然后存入list(或vector等)

例如:

struct word_impl {};   // big thing

auto clone(const word_impl& impl) -> std::unique_ptr<word_impl> {
// clone could if you wished, defer to a virtual clone method
// on word_impl
return std::make_unique<word_impl>(impl);
}


struct word
{
// construct from letters
word(const char* letters) : impl_ { std::make_unique<word_impl>(letters) } { }

// let's make it copyable
word(const word& r) : impl_ { clone(r.impl_) } {}

word& operator=(const word& r) {
if (this != std::addressof(r)) {
impl_ = clone(r.impl_);
}
return *this;
}

// and moveable
word(word&& r) = default;
word& operator=(word&& r) = default;

private:

std::unique_ptr<word_impl> impl_;
}

这是一个完整的、可编译的示例,它根据共享词和可克隆词来表达词对象。

我在这里尝试做的是将“共享”的关注点与对单词的实际操作分开。

这使您可以在客户端使用相同的代码来创建一个由独特词或共享词组成的句子。用户不需要了解单词的内部运作方式,甚至不需要了解其内存是如何管理的。他只需要知道它可以被复制、打印和比较(在这种情况下)。

还有一个进一步的操作,将unique_word转换为shared_word。

#include <memory>
#include <iostream>
#include <vector>
#include <iomanip>
#include <boost/operators.hpp>

//
// define some protocols that a handle class can inherit from. These
// translate methods on the handle onto methods on the implementation
//
template<class Handle>
struct implement_ostream_protocol {
friend std::ostream &operator<<(std::ostream &os, const implement_ostream_protocol &proto) {
auto &ref = static_cast<const Handle &>(proto).get_reference();
return os << ref;
}
};

template<class Handle, class Comp = std::less<>>
struct implement_less_than_protocol {
friend bool operator<(const implement_less_than_protocol &l, const implement_less_than_protocol &r) {
auto &lr = static_cast<const Handle &>(l).get_reference();
auto &rr = static_cast<const Handle &>(r).get_reference();
auto comp = Comp();
return comp(lr, rr);
}
};

template<class Handle>
struct implement_setValue_protocol {
template<class T>
decltype(auto) setValue(T&& value)
{
auto &lr = static_cast<Handle &>(*this).get_reference();
return lr.setValue(std::forward<T>(value));
}
};

//
// this is the implementation of a word
//
struct word_impl {
word_impl(const char *letters) : word_(letters) {
std::cout << "constructed word: " << word_ << std::endl;
}

word_impl(const word_impl &r) : word_(r.word_) {
std::cout << "copied word: " << word_ << std::endl;
}

word_impl(word_impl &&r) noexcept : word_(std::move(r.word_)) {
std::cout << "moved word: " << word_ << std::endl;
}

word_impl &operator=(const word_impl &r) {
if (this != std::addressof(r)) {
word_ = r.word_;
std::cout << "assigned word: " << word_ << std::endl;
}
return *this;
}

word_impl &operator=(word_impl &&r) noexcept {
if (this != std::addressof(r)) {
word_ = std::move(r.word_);
std::cout << "move-assigned word: " << word_ << std::endl;
}
return *this;
}

// some wordy operations
bool comes_before(const word_impl &r) const {
return word_ < r.word_;
}

void setValue(const char* p)
{
std::cout << "value changed from " << word_ << " to " << p << "\n";
word_ = p;
}

// write myself
friend std::ostream &operator<<(std::ostream &os, const word_impl &r) {
return os << std::quoted(r.word_);
}

struct comes_before_op {
bool operator()(const word_impl &l, const word_impl &r) const {
return l.word_ < r.word_;
}
};

std::string word_;
}; // big thing

//
// these are the protocols I want all types of word handles to support
//
template<class Handle>
struct word_impl_protocols
: implement_ostream_protocol<Handle>,
implement_less_than_protocol<Handle, word_impl::comes_before_op> ,
implement_setValue_protocol<Handle>,
boost::less_than_comparable<word_impl_protocols<Handle>>
{

};


auto clone(const word_impl &impl) -> std::unique_ptr<word_impl> {
// clone could if you wished, defer to a virtual clone method
// on word_impl
return std::make_unique<word_impl>(impl);
}


//
// lets make a copyable word that clones its implementation
//
struct unique_word
: word_impl_protocols<unique_word> {
// construct from letters
unique_word(const char *letters) : impl_{std::make_unique<word_impl>(letters)} {}

// let's make it copyable
unique_word(const unique_word &r) : impl_{clone(*r.impl_)} {}

unique_word &operator=(const unique_word &r) {
if (this != std::addressof(r)) {
impl_ = clone(*r.impl_);
}
return *this;
}

// and moveable
unique_word(unique_word &&r) noexcept = default;

unique_word &operator=(unique_word &&r) noexcept = default;

word_impl const &get_reference() const {
return *impl_;
}

word_impl &get_reference() {
return *impl_;
}

// warning - destructive - provides a means to create a
// shared word from a unique_word
auto share() {
return std::shared_ptr<word_impl> {std::move(impl_)};
}

private:

std::unique_ptr<word_impl> impl_;
};

//
// and a word type that shares its implementation
//
struct shared_word
: word_impl_protocols<shared_word> {
shared_word(const char *letters) : impl_{std::make_shared<word_impl>(letters)} {}

shared_word(unique_word &&source) : impl_{source.share()} {}

const word_impl &get_reference() const { return *impl_; }
word_impl &get_reference() { return *impl_; }

std::shared_ptr<word_impl> impl_;
};


int main() {

std::cout << "creating first sentence:\n";
std::vector<unique_word> sentence1 = [] {
std::vector<unique_word> result;
result.emplace_back("abc");
result.emplace_back("def");
result.emplace_back("ghi");
return result;
}();

std::cout << "copying first sentence:\n";
std::vector<unique_word> sentence2 = sentence1;
std::sort(sentence2.begin(), sentence2.end(), std::greater<>());

std::copy(sentence1.begin(), sentence1.end(), std::ostream_iterator<unique_word>(std::cout, ", "));
std::cout << std::endl;

std::copy(sentence2.begin(), sentence2.end(), std::ostream_iterator<unique_word>(std::cout, ", "));
std::cout << std::endl;

std::cout << "converting first sentence to shared words:\n";
std::vector<shared_word> sentence3;
for (auto& unique : sentence1)
{
sentence3.emplace_back(std::move(unique));
}
std::copy(sentence3.begin(), sentence3.end(), std::ostream_iterator<shared_word>(std::cout, ", "));
std::cout << std::endl;

std::cout << "copying sentence of shared words:\n";
auto sentence4 = sentence3;

std::cout << "changing the first word of a shared word sentence:\n";
sentence3.at(0).setValue("xyz");
std::copy(sentence3.begin(), sentence3.end(), std::ostream_iterator<shared_word>(std::cout, ", "));
std::cout << std::endl;
std::copy(sentence4.begin(), sentence4.end(), std::ostream_iterator<shared_word>(std::cout, ", "));
std::cout << std::endl;
}

预期输出:

creating first sentence:
constructed word: abc
constructed word: def
constructed word: ghi
copying first sentence:
copied word: abc
copied word: def
copied word: ghi
"abc", "def", "ghi",
"ghi", "def", "abc",
converting first sentence to shared words:
"abc", "def", "ghi",
copying sentence of shared words:
changing the first word of a shared word sentence:
value changed from abc to xyz
"xyz", "def", "ghi",
"xyz", "def", "ghi",

关于c++ - 内存管理的正确方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41306594/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com