提问人:underloaded_operator 提问时间:4/30/2023 更新时间:5/10/2023 访问量:105
有没有办法在 c++ 中重定向字符串输出
Is there a way to redirect string output in c++
问:
我目前正在处理一个C++项目,我有一些函数可以使用std::cout将一些信息输出到控制台。我还有一个测试函数,可以调用这些函数来检查它们是否正常工作。但是,我发现这些函数的输出在运行测试函数时会分散注意力,我想知道是否有办法将这些函数的输出重定向到文件或完全抑制它。
我尝试使用 ,但不幸的是,这也将我的输出从我的测试函数重定向了。rdbuff
有没有办法在不修改它们的情况下重定向或抑制这些函数的输出?我正在寻找可以在 C++ 11 或更高版本中实现的解决方案。任何帮助将不胜感激。
最终,我想要打印出来的是以下内容:
Test1 PASSED
TEST2 PASSED
TEST3 FAILED
等等......
这是我的代码:
/**
* @author Jakob B
* @file main.cpp [Driver Code]
* @note Driver code for lab4
*
* @brief This assigment focuses on using basic operations in a heap such as:
* - Insertion
* - Deletion
* - Peeking
*
* Those operations were implemented using a Shelter class that includes a struct for Pets
*/
#include <vector>
#include <iostream>
#include <string>
#include <stdexcept>
#include <limits>
#include <utility>
#include <sstream>
#include <unistd.h>
#pragma message("[" __FILE__"] " "Last compiled on [" __DATE__ "] at [" __TIME__"]")
/**
* @struct Pet
* - Defines the Pet object
* - Includes a constructor
*/
struct Pet {
std::string name;
int arrival;
Pet(std::string name = "", int arrival = 0) : name(name), arrival(arrival) {} //Constructor
};
int const PAUSE = 1000000; //usleep const
/**
* @class PetHeap
* - Defines the heap with appropriate methods
*/
class PetHeap {
private:
std::vector<Pet*> petHeap;
void percolateUp(int index);
void percolateDown(int index);
void deleteMin();
Pet* peekMin();
public:
PetHeap();
bool destroyHeap();
void insert(Pet* pet);
void adoptOldestPet();
int numPets();
void displayPets();
std::vector<Pet*> massInsertion();
bool testDestroyHeap();
bool testInsert();
bool testAdoptOldestPet();
bool testNumPets();
bool testDisplayPets();
bool testPercolateUp();
bool testPercolateDown();
bool testDeleteMin();
bool testPeekMin();
void runTests();
};
/** CONSTRUCTOR:
* @name PetHeap::PetHeap()
* @brief Initializes an empty vector for the Pet pointers
*/
PetHeap::PetHeap() {
petHeap = std::vector<Pet*> ();
}
/** DESTRUCTOR:
* @name PetHeap::~PetHeap()
* @brief Handles memory
*/
bool PetHeap::destroyHeap() {
while(!petHeap.empty()){
Pet* value = petHeap[(int)petHeap.size()-1]; //Pet*
petHeap.pop_back(); //resize
delete value;
}
if(petHeap.empty()) {
return true;
}
return false;
}
/**
* @name void PetHeap::percolateUp()
* @brief Percolates up the element at the given index until the heap property is satisfied.
* @param index The index of the element to be percolated up.
*/
void PetHeap::percolateUp(int index) {
/**
* Parent formula: (i-1)/2
*
* Find parent and compare it to the array
*/
int parent = (index-1)/2;
if(index == 0 || petHeap[index] > petHeap[parent]) {
return;
}
//swap the values
std::swap(petHeap[index], petHeap[parent]);
percolateUp(parent);
}
/**
* @name void PetHeap::insert()
* @brief Inserts a new pet into the heap and maintains the heap property
* @param pet The pet to be inserted
*/
void PetHeap::insert(Pet* pet) {
/**
* Insert into the array
* Call percolateUp to maintain the heap
*/
petHeap.push_back(pet);
int index = petHeap.size() - 1; //track the index of the pet
percolateUp((int)index);
}
/**
* @name void PetHeap::percolateDown()
* @brief Percolates down the pet heap from the given index to maintain the heap property
* @param index The index from where to start percolating down
*/
void PetHeap::percolateDown(int index) {
int leftChild = 2*index + 1;
int rightChild = 2*index + 2;
int largestNode = index;
/** @note bad values*/
if(index < 0 || index > petHeap.size()-1) {
return;
}
/** @note no children and it's a leaf node*/
if(leftChild > petHeap.size()-1 && rightChild > petHeap.size()-1) {
return;
}
/** @note node has a left child and the value of the current node is greater*/
if(rightChild >= petHeap.size()-1 && petHeap[index] >= petHeap[leftChild]) {
return;
}
/** @note node has two children and the value of the current node is greater than both children*/
if(petHeap[index] >= petHeap[leftChild] && petHeap[index] >= petHeap[rightChild]) {
return;
}
/** @note recursive case*/
if(petHeap[leftChild] > petHeap[index]) {
largestNode = leftChild;
}
if(rightChild < petHeap.size()-1 && petHeap[rightChild] > petHeap[largestNode]) {
largestNode = rightChild;
}
if(largestNode != index) {
std::swap(petHeap[index], petHeap[largestNode]);
percolateDown(largestNode);
}
}
/**
* @name void PetHeap::deleteMin()
* @brief Deletes the minimum element from the heap.
* If the heap is empty, does nothing. Otherwise, deletes the root element (minimum element)
* from the heap and reorders the heap using percolateDown() to maintain the heap property.
*/
void PetHeap::deleteMin() {
if(petHeap[0] == nullptr) {
return;
}
int lastElementIndex = petHeap.size() - 1;
Pet* lastElement = petHeap[lastElementIndex];
std::swap(petHeap[0], petHeap[lastElementIndex]);
//now the last element is petHeap[0] and the first element is petHeap[lastElementIndex]
delete petHeap[lastElementIndex];
petHeap.resize(petHeap.size()-1);
percolateDown(0); //sort the heap using percolateDown()
}
/**
* @name Pet* PetHeap::peekMin()
* @brief Returns the minimum value of the heap without modifying the heap.
* @return The minimum Pet object in the heap.
*/
Pet* PetHeap::peekMin() {
Pet* firstElement = petHeap[0]; //first element
return firstElement;
}
/**
* @name void PetHeap::adoptOldestPet()
* @brief Adopt the oldest pet in the shelter.
* @return void
*/
void PetHeap::adoptOldestPet() {
if(petHeap.empty()) {
std::cout << "\n[Error: No Pets in the shelter]\n";
return;
}
Pet* oldestPet = peekMin();
std::cout << "\n[Pet adopted]:\n\n";
std::cout << "[name]: " << oldestPet -> name << std::endl;
std::cout << "[arrival]: " << oldestPet -> arrival << std::endl;
std::cout << std::flush;
deleteMin();
return;
}
/**
* @name int PetHeap::numPets()
* @brief Returns the number of pets in the PetHeap.
* @return The number of pets in the PetHeap as an integer.
*/
int PetHeap::numPets() {
std::cout << "\n[Number of Pets]: " << petHeap.size() << "\n\n";
return petHeap.size();
}
/**
* @name void PetHeap::displayPets()
* @brief Display all pets in the shelter
*/
void PetHeap::displayPets() {
std::cout << "\n[Displaying Heap]:\n\n";
if(petHeap.size() == 0) {
std::cout << "[Heap is empty]\n";
}
for(Pet* iter : petHeap) {
std::cout << "[name]: " << iter -> name << std::flush; //flush buffer
std::cout << "\t[arrival]: "<< iter -> arrival << std::endl;
}
return;
}
/** @name getName()
* @brief Prompts the user to enter a name
* @param name passed by reference
* @return std::string name
*/
std::string getName(std::string &name) {
std::cout << "[Enter Name]: ";
while (true) {
try {
std::cin >> name;
if (std::cin.fail()) {
throw std::runtime_error("[Invalid input. Please enter a valid name]");
}
return name;
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
std::cin.clear();
std::cin.ignore(10000, '\n');
}
}
}
/** @name getArrival()
* @brief Prompts the user to enter the arrival time
* @param arrival passed by reference
* @return (int) arrival
*/
int getArrival(int &arrival) {
std::cout << "\n[Enter Arrival]: ";
while (true) {
try {
std::cin >> arrival;
if (std::cin.fail() || arrival < 0) {
throw std::runtime_error("[Invalid input. Please enter a positive integer]");
}
return arrival;
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
std::cin.clear();
std::cin.ignore(10000, '\n');
std::cout << "\n[Enter Arrival]: ";
}
}
}
/**
* @name int getInput()
* @brief gets the input for the switch statement
* @return (int) input
*/
int getInput() {
int const MIN = 1;
int const MAX = 7;
int choice = 0;
std::cout << "\n[Enter]: ";
while (true) {
try {
std::cin >> choice;
if (std::cin.fail()) { //std::cin.fail() if the input is not an intiger returns true
/// @link https://cplusplus.com/forum/beginner/2957/
std::cin.clear(); // clear error flags
std::cin.ignore(10000, '\n'); // ignore up to 10000 characters or until a newline is encountered
throw std::invalid_argument("[Invalid input]");
}
else if (choice < MIN || choice > MAX) {
throw std::out_of_range("[Input out of range. Please enter an integer between 1 and 16]");
}
else {
return choice;
}
}
catch (const std::exception& error) {
std::cout << error.what() << std::endl;
std::cout << "[Re-enter]: ";
}
}
}
/** @name goodbye()
* @brief The function prompts the user goodbye
* @remark Handles UI
* @return void-type
*/
void goodbye() {
std::cout << "\nGoodbye!\n\n";
}
/**
* @brief Destroys the heap and prints a message to the console
* @param heap A reference to the `PetHeap` object to be destroyed.
*/
void isDestroyed(PetHeap &heap) {
bool dead = false;
bool retry = false;
dead = heap.destroyHeap();
if(dead) {
std::cout << "\n[Heap Destroyed]\n";
goodbye();
} else {
std::cout << "\n[Something went wrong]\n";
retry = heap.destroyHeap(); //try again
if(retry == false) {
std::cout << "\n[Program is leaking memory!]\n";
std::cout << "\n[Force Exiting with code 1]\n";
std::exit(EXIT_FAILURE);
}
}
}
/**
* @name void menu()
* @brief Prints the menu for the user
*/
void menu() {
std::cout << "\n\n"
<< "[1] Insert a Pet\n"
<< "[2] Adopt a Pet\n"
<< "[3] Number of Pets in the Heap\n"
<< "[4] Display Heap\n"
<< "[5] Run Tests\n"
<< "[6] Exit\n";
return;
}
/** @name printTitle()
* @brief The function prints the title
* @remark Handles UI
* @return void-type
*/
void printTitle() {
std::cout << "\n\n*** Welcome to the Heap assigment *** \n\n";
std::cout << "Please select one of the following?\n";
}
/**
*
*/
std::vector<Pet*> PetHeap::massInsertion() {
PetHeap heap;
std::vector<std::string> namesInput = {"F", "G", "E", "A", "B", "K", "L", "Q", "T", "Y", "O", "M"}; //12
std::vector<int> arrivalInput = {2, 6, 12, 3, 7, 18, 36, 6, 9, 11, 10, 29}; //12
std::vector<Pet*> inputValues; //vector with Pet pointers
inputValues.reserve(namesInput.size());
for(int i = 0; i < namesInput.size(); i++) {
inputValues.emplace_back(new Pet(namesInput[i], arrivalInput[i]));
}
return inputValues;
}
/**
*
*/
bool PetHeap::testDestroyHeap() {
//test destroying a heap with pets
std::vector<Pet*> pets = massInsertion();
bool done = destroyHeap();
std::cout << "TEST1 FINISHED\n" << std::flush;
usleep(PAUSE);
return done && petHeap.empty();
}
bool PetHeap::testInsert() {
//inserting a single pet
Pet* pet1 = new Pet("Fido", 3);
insert(pet1);
bool result1 = peekMin() == pet1 && petHeap.size() == 1;
//inserting multiple pets
std::vector<std::pair<std::string, int>> newPets = {{"Rufus", 6}, {"Buddy", 2}};
for (auto pet : newPets) {
Pet* newPet = new Pet(pet.first, pet.second);
insert(newPet);
}
bool result2 = peekMin()->name == "Buddy" && petHeap.size() == 3;
std::cout << "TEST2 FINISHED\n" << std::flush;
usleep(PAUSE);
return result1 && result2;
}
bool PetHeap::testAdoptOldestPet() {
//adopting the oldest pet from a heap with pets
std::vector<Pet*> pets = massInsertion();
Pet* oldestPet = pets[0];
bool result1 = false;
if (!pets.empty()) {
result1 = destroyHeap() && peekMin() != oldestPet && petHeap.size() == pets.size() - 1;
}
//adopting the oldest pet from an empty heap
destroyHeap();
adoptOldestPet();
bool result2 = petHeap.empty();
std::cout << "TEST3 FINISHED\n" << std::flush;
usleep(PAUSE);
return result1 && result2;
}
bool PetHeap::testNumPets() {
//getting the number of pets in a heap with pets
std::vector<Pet*> pets = massInsertion();
bool result1 = false;
if (!pets.empty()) {
for (auto pet : pets) {
insert(pet);
}
result1 = numPets() == pets.size();
}
//getting the number of pets in an empty heap
destroyHeap();
bool result2 = numPets() == 0;
std::cout << "TEST4 FINISHED\n" << std::flush;
usleep(PAUSE);
return result1 && result2;
}
bool PetHeap::testDisplayPets() {
//displaying the pets in a heap with pets
std::vector<Pet*> pets = massInsertion();
bool result1 = false;
std::ostringstream oss; //declare oss block
if (!pets.empty()) {
for (auto pet : pets) {
insert(pet);
}
displayPets();
//fix oss
result1 = oss.str() == "A(2) B(7) E(12) F(2) G(6) K(18) L(36) M(29) O(10) Q(6) T(9) Y(11) ";
}
//displaying the pets in an empty heap
oss.str("");
destroyHeap();
displayPets();
bool result2 = oss.str() == "";
std::cout << "TEST5 FINISHED\n" << std::flush;
usleep(PAUSE);
return result1 && result2;
}
bool PetHeap::testPercolateUp() {
std::vector<Pet*> inputValues = massInsertion();
int index = inputValues.size() / 2;
int parentIndex = (index - 1) / 2;
//percolating up an element
Pet* pet = new Pet("Fido", 5);
petHeap[index] = pet;
percolateUp(index);
bool result1 = petHeap[parentIndex] == pet;
//percolating up an element that's already at the root
percolateUp(0);
bool result2 = true;
std::cout << "TEST6 FINISHED\n" << std::flush;
usleep(PAUSE);
return result1 && result2;
}
bool PetHeap::testPercolateDown() {
std::vector<Pet*> inputValues = massInsertion();
int index = 0;
int leftChildIndex = 2 * index + 1;
int rightChildIndex = 2 * index + 2;
//percolating down an element
Pet* pet = new Pet("Fido", 5);
petHeap[index] = pet;
percolateDown(index);
bool result1 = petHeap[leftChildIndex] == pet;
//percolating down an element that's already a leaf
petHeap[leftChildIndex] = petHeap.back();
petHeap.pop_back();
percolateDown(leftChildIndex);
bool result2 = true;
std::cout << "TEST7 FINISHED\n" << std::flush;
usleep(PAUSE);
return result1 && result2;
}
bool PetHeap::testDeleteMin() {
std::vector<Pet*> inputValues = massInsertion();
//deleting the minimum element
Pet* minPet = peekMin();
deleteMin();
bool result1 = peekMin() != minPet && petHeap.size() == inputValues.size() - 1;
//deleting the minimum element from an empty heap
destroyHeap();
deleteMin();
bool result2 = petHeap.empty();
std::cout << "TEST8 FINISHED\n" << std::flush;
usleep(PAUSE);
return result1 && result2;
}
bool PetHeap::testPeekMin() {
std::vector<Pet*> inputValues = massInsertion();
//peeking at the minimum element
Pet* minPet = peekMin();
bool result1 = minPet != nullptr && minPet->arrival == 2;
//peeking at the minimum element of an empty heap
destroyHeap();
Pet* emptyMinPet = peekMin();
bool result2 = emptyMinPet == nullptr;
std::cout << "TEST9 FINISHED\n" << std::flush;
usleep(PAUSE);
return result1 && result2;
}
/**
* @name void runTests()
* @brief Runs tests for all the functions
*/
void PetHeap::runTests() {
std::vector<bool> testValues;
std::cout << "\n*** RUNNING ALL TESTS ***\n\n" << std::flush;
usleep(PAUSE);
testValues.push_back(testDestroyHeap());
testValues.push_back(testInsert());
testValues.push_back(testAdoptOldestPet());
testValues.push_back(testNumPets());
testValues.push_back(testDisplayPets());
testValues.push_back(testPercolateUp());
testValues.push_back(testPercolateDown());
testValues.push_back(testDeleteMin());
testValues.push_back(testPeekMin());
for(auto i = 0; i < testValues.size(); i++) {
if(testValues[i] == true) {
std::cout << "TEST " << i+1 << " PASSED ***";
}else if(testValues[i] == false) {
std::cout << "TEST " << i+1 << " FAILED ###";
}
}
}
/**
* @brief Main function of the program
* @return EXIT_SUCESS upon succesful execution
*/
int main() {
PetHeap heap;
std::string name = "";
int arrival = 0;
enum OP_ID {
ID_1 = 1,
ID_2,
ID_3,
ID_4,
ID_5,
ID_6,
};
printTitle();
while(true) {
menu();
switch(getInput()) {
case OP_ID::ID_1: {
heap.insert(new Pet(getName(name), getArrival(arrival)));
break;
}
case OP_ID::ID_2: {
heap.adoptOldestPet();
break;
}
case OP_ID::ID_3: {
heap.numPets();
break;
}
case OP_ID::ID_4: {
heap.displayPets();
break;
}
case OP_ID::ID_5: {
heap.runTests();
break;
}
case OP_ID::ID_6: {
isDestroyed(heap);
exit(EXIT_SUCCESS);
break;
}
default: {
/** @note do nothing*/
}
}
}
return EXIT_SUCCESS;
}
代码有一些错误,并且缺少一些文档,因为我还没有完成实验。我希望这不会出现和问题,但万一出现,我非常抱歉。
答: 暂无答案
上一个:功率:遇到无限表达式 1/0
下一个:快速排序速度明显变慢
评论
rdbuf
std::cerr
std::cout
/dev/null
std::cout
rdbuf()
std::ostream
std::cout
std::cerr