Временный объект класса - PullRequest
1 голос
/ 17 июня 2020

В настоящее время я читаю пятое издание праймера по С ++, и это один из примеров кода, которые были в книге. Меня смущает эта строка кода auto ret = StrBlobPtr(*this, data->size());, если я правильно понимаю, эта строка создает временный объект StrBlobPtr и вызывает этот конструктор StrBlobPtr(StrBlob& a, size_t sz = 0) : wptr(a.data), curr(sz) {}, но я не понимаю, как auto ret= получает возвращаемое значение из временного объекта , поэтому мои вопросы:

  1. Как ret получает объект, созданный StrBlobPtr?
  2. Как end возвращает StrBlobPtr, содержащий последний значение в std::shared_ptr<vector<string>> data; внутри класса StrBlob.

Часть кода, о которой я говорю, находится полностью внизу.

#pragma once

#include <vector>
#include <string>
#include <initializer_list>
#include<stdexcept>
#include <memory>
#include <exception>

using std::vector;
using std::string;

class StrBlobPtr;

class StrBlob {
public:
    using size_type = vector<string>::size_type;
    friend class StrBlobPtr;

    StrBlobPtr begin();
    StrBlobPtr end();

    StrBlob() : data(std::make_shared<vector<string>>()) {}
    StrBlob(std::initializer_list<string> il)
        : data(std::make_shared<vector<string>>(il))
    {
    }

    size_type size() const { return data->size(); }
    bool empty() const { return data->empty(); }

    void push_back(const string& t) { data->push_back(t); }
    void pop_back()
    {
        check(0, "pop_back on empty StrBlob");
        data->pop_back();
    }

    std::string& front()
    {
        check(0, "front on empty StrBlob");
        return data->front();
    }

    std::string& back()
    {
        check(0, "back on empty StrBlob");
        return data->back();
    }

    const std::string& front() const
    {
        check(0, "front on empty StrBlob");
        return data->front();
    }
    const std::string& back() const
    {
        check(0, "back on empty StrBlob");
        return data->back();
    }

private:
    void check(size_type i, const string& msg) const
    {
        if (i >= data->size()) throw std::out_of_range(msg);
    }
private:
    std::shared_ptr<vector<string>> data;
};

class StrBlobPtr {
public:
    StrBlobPtr() : curr(0) {}
    StrBlobPtr(StrBlob& a, size_t sz = 0) : wptr(a.data), curr(sz) {}
    bool operator!=(const StrBlobPtr& p) { return p.curr != curr; }
    string& deref() const
    {
        auto p = check(curr, "dereference past end");
        return (*p)[curr];
    }
    StrBlobPtr& incr()
    {
        check(curr, "increment past end of StrBlobPtr");
        ++curr;
        return *this;
    }

private:
    std::shared_ptr<vector<string>> check(size_t i, const string& msg) const
    {
        auto ret = wptr.lock();
        if (!ret) throw std::runtime_error("unbound StrBlobPtr");
        if (i >= ret->size()) throw std::out_of_range(msg);
        return ret;
    }
    std::weak_ptr<vector<string>> wptr;
    size_t curr;
};
StrBlobPtr StrBlob::begin() { return StrBlobPtr(*this); }
StrBlobPtr StrBlob::end()
{
    auto ret = StrBlobPtr(*this, data->size());
    return ret;
}

1 Ответ

2 голосов
/ 17 июня 2020

Начиная с c ++ 11, вы можете использовать ключевое слово auto , если вы не хотите явно указывать тип переменной, но не путайте его с автоматическими c переменными, что означает, что они удаляется в конце блока (вы можете прочитать это: cppreference ).

Итак, в первой строке функции вызывается StrBlobPtr :: end () конструктор, создается объект типа StrBlobPtr , после вызова этого конструктора копирования создается другой объект, но этот объект будет существовать до тех пор, пока не будет достигнут конец блока (в данном случае - конец функции). После этого первый объект удаляется, поэтому у вас остается только объект, созданный конструктором копирования. Пожалуйста, проверьте этот пост: ссылка .

Ваш второй вопрос касается возврата объекта, если я прав. Вы должны быть осторожны, когда делаете это в C ++. Предположим, вы вызвали StrBlobPtr :: end () где-то в вашем коде:

StrBlobPtr obj; 
obj = StrBlobPtr::end();

Итак, вы создали объект в первой строке, после этого вы вызываете функцию, возвращается объект того же типа но этот объект существует только в этой строке, после вызова StrBlobPtr :: operator = (StrBlobPtr x) объект, возвращаемый функцией, удаляется и не существует в памяти, поэтому вы не можете сделать:

StrBlobPtr* obj; 
obj = StrBlobPtr::end();

потому что после указателя второй строки obj имеет адрес удаленного объекта, и если вы попытаетесь его использовать, вы получите исключение. Поэтому вы должны быть осторожны, если хотите вернуть из функции весь объект, иногда лучше создать объект в динамической c памяти с помощью оператора new и вернуть ссылку или указатель из функции. Важно, если вы вызываете эту функцию часто, каждый раз, когда вам нужно создать объект и вызвать конструктор копирования, чтобы вернуть этот объект.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...