I am trying to understand why the class destructor is being called right at the beginning after the program starts !?
Here is my program snippet:
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <mutex>
#include <atomic>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <linux/can.h>
#include <linux/can/raw.h>
class Canloop {
private:
int socketFileDescriptor;
struct sockaddr_can socketAdressConfig;
struct ifreq interfaceRequestConfig;
struct can_frame canFrameRx;
struct can_frame canFrameTx;
int sendCounter{0};
std::thread receive_;
std::thread transmit_;
std::mutex readWriteMutex;
std::atomic<bool> running{true};
void receiveThread();
void transmitThread();
public:
Canloop(std::string &canInterface);
void setCanData(can_frame &);
void start();
void stop();
~Canloop();
};
Canloop::Canloop(std::string &canInterface) {
if ((socketFileDescriptor = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
perror("Socket");
}
strcpy(interfaceRequestConfig.ifr_name, canInterface.c_str());
ioctl(socketFileDescriptor, SIOCGIFINDEX, &interfaceRequestConfig);
memset(&socketAdressConfig, 0, sizeof(socketAdressConfig));
socketAdressConfig.can_family = AF_CAN;
socketAdressConfig.can_ifindex = interfaceRequestConfig.ifr_ifindex;
if (bind(socketFileDescriptor, (struct sockaddr *)&socketAdressConfig, sizeof(socketAdressConfig)) < 0) {
perror("Bind");
}
int flags = fcntl(socketFileDescriptor, F_GETFL, 0);
if (flags == -1) {
perror("fcntl non blocking set error");
}
flags != O_NONBLOCK;
if (fcntl(socketFileDescriptor, F_SETFL, flags) == -1) {
perror("fcntl");
}
int bufferSize = 2;
if (setsockopt(socketFileDescriptor, SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize))) {
perror("setsocketopt");
}
if (setsockopt(socketFileDescriptor, SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize))) {
perror("setsocketopt");
}
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 1000;
if (setsockopt(socketFileDescriptor, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout))) {
perror("time set error");
}
if (setsockopt(socketFileDescriptor, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout))) {
perror("time set error");
}
}
void Canloop::start() {
receive_ = std::thread([=] { receiveThread(); });
transmit_ = std::thread([=] { transmitThread(); });
}
void Canloop::setCanData(can_frame &data) {
this->canFrameTx = data;
}
void Canloop::stop() {
if (close(socketFileDescriptor) < 0) {
perror("Close");
}
running = false;
if (receive_.joinable()) {
receive_.join();
}
if (transmit_.joinable()) {
transmit_.join();
}
}
void Canloop::receiveThread() {
std::cout << "Starting Rx_ " << std::endl;
while (running) {
ssize_t bytesRead;
{
// Mutex to guard the socket for Read access
std::lock_guard<std::mutex> lock(readWriteMutex);
bytesRead = read(socketFileDescriptor, &canFrameRx, sizeof(struct can_frame));
}
if (running) {
if (bytesRead == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// Handle non-blocking read
} else {
perror("read error");
}
} else if (bytesRead == sizeof(struct can_frame)) {
// Print data
printf("0x%03X [%d] ", canFrameRx.can_id, canFrameRx.can_dlc);
for (int i = 0; i < canFrameRx.can_dlc; i++)
printf("%02X ", canFrameRx.data[i]);
printf("\r\n");
} else {
std::cout << "Incomplete data" << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
}
void Canloop::transmitThread() {
std::cout << "Starting Tx_" << std::endl;
while (running) {
ssize_t nbytes ;
{
// Lock for write
std::lock_guard<std::mutex> lock(readWriteMutex);
nbytes = write(socketFileDescriptor, &canFrameTx, sizeof(struct can_frame));
}
if (running && nbytes == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
std::cout << "Would block" << std::endl;
} else if (errno == ENOBUFS) {
perror("Buffer fail: ");
} else {
perror("Write fail");
}
}
std::cout << "Data written " << sendCounter++ << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
Canloop::~Canloop() {
std::cout << "Destructor called" << std::endl;
if (transmit_.joinable()) {
transmit_.join();
}
if(receive_.joinable()) {
receive_.join();
}
}
int main() {
std::string canInterface("can0");
Canloop cantester(canInterface);
can_frame localCanData;
char hello[5] = "Hell";
localCanData.can_id = 0x123;
localCanData.can_dlc = sizeof(hello) / sizeof(hello[0]);
sprintf((char *)localCanData.data, hello);
cantester.setCanData(localCanData);
cantester.start();
return 0;
}
As i never shutdown the program, neither destroy the class explicitly, the destructor should not be invoked. Yet i see the following output.
Starting Rx_
Starting Tx_
Destructor called
Data written 0
Data written 1
Data written 2
Data written 3
Data written 4
Data written 5
Data written 6
Data written 7
Data written 8
Data written 9
Why is it being called ? I do not expect an invoke !?