Я имею дело с объектами C++, которые используют деструктор для освобождения ресурсов. При передаче этих объектов функции с произвольным количеством параметров. Есть ли способ избавиться от использования указателей в этом случае?
Одним из возможных решений является передача вектора указателей на эти объекты. если я передам сами объекты, деструкторы будут вызываться дважды, один из них - реальные объекты, другой - когда вектор освобождается.
#include<iostream>
#include<vector>
class integer {
private:
int data;
public:
integer(int value = 0): data(value) {}
~integer() {}
void increase() {
data++;
}
friend std::ostream& operator<<(std::ostream& os, const integer& x);
};
std::ostream& operator<<(std::ostream& os, const integer& x) {
os << x.data;
return os;
}
void foo(std::vector<integer*> vec) {
for (auto it = vec.begin(); it != vec.end(); it++) {
(*it)->increase();
}
}
int main() {
integer x1(3);
integer x2(4);
integer x3(5);
std::cout << x1 << " " << x2 << " " << x3 << std::endl;
foo({&x1, &x2, &x3});
std::cout << x1 << " " << x2 << " " << x3 << std::endl;
return 0;
}
Ожидаемые результаты:
3 4 5
4 5 6
the deconstructors will be called twice, one is the real objects, another is when the vector is deallocated.
Это не совсем так, потому что эти объекты будут скопированы, поэтому есть две копии каждого, и обе должны быть освобождены.
Показанный выше код соответствует требованию. Актуальный вопрос заключается в том, как избавиться от использования указателей. Спасибо
Зачем вообще использовать указатели?
Почему? Что не так с указателями? Это именно та собственность, которую вы хотите.
@Quimby Почему бы не передать вектор в качестве ссылки: от void foo(std::vector<integer*> vec)
до void foo(std::vector<integer>& vec)
?
@Quimby Поскольку C++ предоставляет ссылки, лучше не использовать указатели.
@Timo Потому что тогда он не будет увеличивать целые числа x1, x2, x3
в main.
@Timo Я проверял это, компилятор создаст вектор целочисленных объектов, который вызывает конструктор копирования и, наконец, вызывает деструктор.
Ха, шутка надо мной. Извини за это.
@ Тимо Бывает :)
Возможный дубликат Почему я не могу сделать вектор ссылок?
@jaket О, да, это дублируется.
Я не уверен, что не так с указателями, но, конечно, вы можете избежать указателей с помощью reference_wrapper
s. (Не забудьте #include <functional>
)
void foo(const std::vector<std::reference_wrapper<integer>>& vec)
{
for (auto it = vec.begin(); it != vec.end(); it++) {
(*it)->increase();
}
}
Теперь вы можете называть это как foo({x1, x2, x3})
.
Вы даже можете избавиться от {}
, если хотите:
template <typename... Args>
void foo(Args&... args)
{
static_assert(std::conjunction_v<std::is_same<Args, integer>...>);
(args.increase(), ...);
}
(Не забудьте #include <type_traits>
.)
Теперь вы можете называть это как foo(x1, x2, x3)
.
Я пробовал живую демонстрацию, работает ли std::reference_wrapper<type>
только на компиляторе Clang? gcc выдает ошибки.
@NgọcKhánhNguyễn Плохо! Я забыл #include <functional>
. Я обновил демо.
Вы можете использовать итераторы. Как только у вас будет больше 3, вы не должны продолжать x4
, но все равно используйте контейнер. Ваш foo
будет
template <typename iterator_t>
void foo(iterator_t begin,iterator_t end) {
for ( ; begin != end; ++begin) begin->increase();
}
И в main
:
int main() {
std::vector<integer> x { {3},{4},{5} };
for (const auto& i : x) std::cout << i << " ";
std::cout << "\n";
foo(x.begin(),x.end());
for (const auto& i : x) std::cout << i << " ";
return 0;
}
Нет, деструктор
vector
вызывает деструкторinteger*
, который не работает и не вызывает деструкторinteger
.