Arduino自定义库编译报错:使用已删除函数问题求助
编译错误解决:TFT_eSPI类赋值运算符被删除问题
问题背景
开发基于Arduino的自定义库,依赖TFT_eSPI库,编译时出现赋值运算符相关错误,且drawGIF函数必须保持静态。
编译错误信息
/.../sketch/src/Display/Display.cpp: In static member function 'static void Display::begin()': /.../sketch/src/Display/Display.cpp:16:9: error: use of deleted function 'TFT_eSPI& TFT_eSPI::operator=(TFT_eSPI&&)' tft = TFT_eSPI(); ^ In file included from /.../sketch/src/Display/Display.h:12:0, from /.../sketch/src/Display/Display.cpp:9: /Users/luigisc/Documents/Arduino/libraries/TFT_eSPI/TFT_eSPI.h:359:7: note: 'TFT_eSPI& TFT_eSPI::operator=(TFT_eSPI&&)' is implicitly deleted because the default definition would be ill-formed: class TFT_eSPI : public Print { ^ /Users/luigisc/Documents/Arduino/libraries/TFT_eSPI/TFT_eSPI.h:359:7: error: non-static reference member 'fs::FS& TFT_eSPI::fontFS', can't use default assignment operator
相关代码
Display.cpp
#include "Arduino.h" #include "Display.h" /*Global objects' declaration and initialization*/ void Display::begin(){ //Display initializing tft = TFT_eSPI(); tft.fillScreen(TFT_BLACK); tft.setTextColor(TFT_WHITE); tft.setTextSize(2); tft.setRotation(1); } // PRIVATE FUNCTIONS void Display::drawGIF(GIFDRAW *pDraw){ uint8_t *s; uint16_t *d, *usPalette, usTemp[320]; int x, y, iWidth; iWidth = pDraw->iWidth; if (iWidth > tft.width()) iWidth = tft.width(); usPalette = pDraw->pPalette; y = pDraw->iY + pDraw->y; // current line s = pDraw->pPixels; if (pDraw->ucDisposalMethod == 2) // restore to background color { for (x=0; x<iWidth; x++) { if (s[x] == pDraw->ucTransparent) s[x] = pDraw->ucBackground; } pDraw->ucHasTransparency = 0; } // Apply the new pixels to the main image if (pDraw->ucHasTransparency) // if transparency used { uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent; int x, iCount; pEnd = s + iWidth; x = 0; iCount = 0; // count non-transparent pixels while(x < iWidth) { c = ucTransparent-1; d = usTemp; while (c != ucTransparent && s < pEnd) { c = *s++; if (c == ucTransparent) // done, stop { s--; // back up to treat it like transparent } else // opaque { *d++ = usPalette[c]; iCount++; } } // while looking for opaque pixels if (iCount) // any opaque pixels? { tft.setAddrWindow(pDraw->iX+x, y, iCount, 1); tft.startWrite(); tft.pushPixels(usTemp, iCount); tft.endWrite(); x += iCount; iCount = 0; } // no, look for a run of transparent pixels c = ucTransparent; while (c == ucTransparent && s < pEnd) { c = *s++; if (c == ucTransparent) iCount++; else s--; } if (iCount) { x += iCount; // skip these iCount = 0; } } } else { s = pDraw->pPixels; // Translate the 8-bit pixels through the RGB565 palette (already byte reversed) for (x=0; x<iWidth; x++) usTemp[x] = usPalette[*s++]; tft.setAddrWindow(pDraw->iX, y, iWidth, 1); tft.startWrite(); tft.pushPixels(usTemp, iWidth); tft.endWrite(); } } // PUBLIC FUNCTIONS void Display::displayGIF(const uint8_t *gif_file, int gif_size, int nTimes){ if (gif.open((uint8_t *)gif_file, gif_size, drawGIF)){ for(int i=0;i<nTimes;i++){ gif.playFrame(true, NULL); while(gif.playFrame(true, NULL)){} } gif.close(); }else{ tft.fillScreen(TFT_BLACK); tft.setTextColor(TFT_WHITE); tft.setTextSize(2); tft.drawString("ERR: Can't load GIF", 0, tft.width()/2); } }
Display.h
#ifndef DISPLAY_H #define DISPLAY_H #include "Arduino.h" #include <TFT_eSPI.h> #include <AnimatedGIF.h> class Display { public: static void begin(); static void displayGIF(const uint8_t *gif_file, int gif_size, int nTimes); private: static void drawGIF(GIFDRAW *pDraw); static AnimatedGIF gif; static TFT_eSPI tft; }; #endif
错误原因
TFT_eSPI类包含非静态引用成员fs::FS& fontFS,C++规则中,包含引用成员的类会自动删除默认的赋值运算符(拷贝赋值、移动赋值均被删除)。begin()函数中执行tft = TFT_eSPI();,本质是用临时对象给静态成员tft做移动赋值,触发了被删除的运算符。
解决方法
方案1:直接初始化静态成员(推荐)
静态成员需在类外部初始化,直接创建TFT_eSPI实例,无需在begin()中赋值:
- 修改
Display.cpp,在文件开头添加静态成员的定义和初始化:
#include "Arduino.h" #include "Display.h" // 初始化静态成员 AnimatedGIF Display::gif; TFT_eSPI Display::tft; // 直接调用默认构造函数初始化 void Display::begin(){ // 移除 tft = TFT_eSPI(); 这一行 tft.fillScreen(TFT_BLACK); tft.setTextColor(TFT_WHITE); tft.setTextSize(2); tft.setRotation(1); } // 其余代码保持不变
Display.h中的静态成员声明无需修改。
方案2:使用指针动态创建实例(适合动态配置场景)
若需要在begin()中传入参数初始化TFT_eSPI,可改用指针:
- 修改
Display.h的静态成员声明为指针:
private: static void drawGIF(GIFDRAW *pDraw); static AnimatedGIF gif; static TFT_eSPI* tft; // 改为指针类型
- 在
Display.cpp中初始化指针并在begin()中创建实例:
#include "Arduino.h" #include "Display.h" AnimatedGIF Display::gif; TFT_eSPI* Display::tft = nullptr; // 初始化为空指针 void Display::begin(){ if(tft == nullptr){ tft = new TFT_eSPI(); // 动态创建实例 } tft->fillScreen(TFT_BLACK); tft->setTextColor(TFT_WHITE); tft->setTextSize(2); tft->setRotation(1); } // 所有使用tft的地方改为指针调用(->),比如drawGIF函数中的: // tft->setAddrWindow(...) // tft->startWrite() 等
方案3:使用std::optional延迟初始化(C++17及以上)
若编译器支持C++17,可用std::optional包装TFT_eSPI:
- 修改
Display.h:
#include <optional> // 引入头文件 class Display { private: static void drawGIF(GIFDRAW *pDraw); static AnimatedGIF gif; static std::optional<TFT_eSPI> tft; // 用optional包装 };
- 在
Display.cpp中初始化并在begin()中构造:
#include "Arduino.h" #include "Display.h" AnimatedGIF Display::gif; std::optional<TFT_eSPI> Display::tft; void Display::begin(){ if(!tft.has_value()){ tft.emplace(); // 构造TFT_eSPI实例 } auto& tft_ref = *tft; // 获取引用方便后续调用 tft_ref.fillScreen(TFT_BLACK); tft_ref.setTextColor(TFT_WHITE); tft_ref.setTextSize(2); tft_ref.setRotation(1); }
注意事项
- 方案1最简洁高效,符合Arduino编程习惯,优先选择。
- 使用方案2时,可在程序结束时手动
delete tft;避免内存泄漏(Arduino平台通常无需处理,但严谨起见可添加)。 drawGIF函数保持静态不受影响,静态成员的访问权限不受函数静态性限制。
内容的提问来源于stack exchange,提问作者Luigi Schiavone
相关产品推荐
相关产品推荐

